diff --git a/cmd/tools/vast/vast.v b/cmd/tools/vast/vast.v index 5e2ba843b2..d38a95accb 100644 --- a/cmd/tools/vast/vast.v +++ b/cmd/tools/vast/vast.v @@ -596,6 +596,7 @@ fn (t Tree) fn_decl(node ast.FnDecl) &Node { obj.add_terse('is_variadic', t.bool_node(node.is_variadic)) obj.add('is_anon', t.bool_node(node.is_anon)) obj.add_terse('is_noreturn', t.bool_node(node.is_noreturn)) + obj.add_terse('is_weak', t.bool_node(node.is_weak)) obj.add_terse('is_manualfree', t.bool_node(node.is_manualfree)) obj.add('is_main', t.bool_node(node.is_main)) obj.add('is_test', t.bool_node(node.is_test)) @@ -840,6 +841,8 @@ fn (t Tree) global_field(node ast.GlobalField) &Node { obj.add_terse('typ', t.type_node(node.typ)) obj.add_terse('has_expr', t.bool_node(node.has_expr)) obj.add_terse('is_markused', t.bool_node(node.is_markused)) + obj.add_terse('is_weak', t.bool_node(node.is_weak)) + obj.add_terse('is_hidden', t.bool_node(node.is_hidden)) obj.add('comments', t.array_node_comment(node.comments)) obj.add('pos', t.pos(node.pos)) obj.add('typ_pos', t.pos(node.typ_pos)) diff --git a/vlib/readline/readline_nix.c.v b/vlib/readline/readline_nix.c.v index c34e49c6b8..64b01b81e9 100644 --- a/vlib/readline/readline_nix.c.v +++ b/vlib/readline/readline_nix.c.v @@ -10,6 +10,7 @@ module readline import term.termios import term import os +import encoding.utf8.east_asian fn C.raise(sig int) @@ -379,12 +380,16 @@ fn (mut r Readline) refresh_line() { } else { r.prompt } - end_of_input = calculate_screen_position(last_prompt_line.len, 0, get_screen_columns(), - r.current.len, end_of_input) + last_prompt_width := east_asian.display_width(last_prompt_line, 1) + current_width := east_asian.display_width(r.current.string(), 1) + cursor_prefix_width := east_asian.display_width(r.current[..r.cursor].string(), 1) + + end_of_input = calculate_screen_position(last_prompt_width, 0, get_screen_columns(), + current_width, end_of_input) end_of_input[1] += r.current.filter(it == `\n`).len mut cursor_pos := [0, 0] - cursor_pos = calculate_screen_position(last_prompt_line.len, 0, get_screen_columns(), - r.cursor, cursor_pos) + cursor_pos = calculate_screen_position(last_prompt_width, 0, get_screen_columns(), + cursor_prefix_width, cursor_pos) shift_cursor(0, -r.cursor_row_offset) term.erase_toend() print(last_prompt_line) @@ -392,7 +397,7 @@ fn (mut r Readline) refresh_line() { if end_of_input[0] == 0 && end_of_input[1] > 0 { print('\n') } - shift_cursor(cursor_pos[0] - r.prompt_offset, -(end_of_input[1] - cursor_pos[1])) + shift_cursor(cursor_pos[0], -(end_of_input[1] - cursor_pos[1])) r.cursor_row_offset = cursor_pos[1] } diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 484ab59c3f..cdf72c96f7 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -446,6 +446,7 @@ pub: module_pos int = -1 // module: is_union bool is_option bool + is_aligned bool attrs []Attr pre_comments []Comment end_comments []Comment @@ -593,6 +594,7 @@ pub: is_c_extern bool is_variadic bool is_anon bool + is_weak bool is_noreturn bool // true, when @[noreturn] is used on a fn is_manualfree bool // true, when @[manualfree] is used on a fn is_main bool // true for `fn main()` @@ -967,6 +969,8 @@ pub: is_markused bool // an explicit `@[markused]` tag; the global will NOT be removed by `-skip-unused` is_volatile bool is_exported bool // an explicit `@[export]` tag; the global will NOT be removed by `-skip-unused` + is_weak bool + is_hidden bool pub mut: expr Expr typ Type diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 3d01708eed..5443519302 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -38,6 +38,10 @@ pub mut: // json bool // json is imported comptime_calls map[string]bool // resolved name to call on comptime comptime_syms map[Type]bool // resolved syms (generic) + // + used_attr_noreturn bool // @[noreturn] + used_attr_hidden bool // @[hidden] + used_attr_weak bool // @[weak] } @[unsafe] diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index 9567c77cf5..6d855fbe0c 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -1018,6 +1018,30 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr, mut sb strings.Builder) ( } .eq, .ne, .gt, .lt, .ge, .le { match mut cond.left { + ast.AtExpr { + // @OS == 'linux' + left_type := c.expr(mut cond.left) + right_type := c.expr(mut cond.right) + if !c.check_types(right_type, left_type) { + left_name := c.table.type_to_str(left_type) + right_name := c.table.type_to_str(right_type) + c.error('mismatched types `${left_name}` and `${right_name}`', + cond.pos) + } + left_str := cond.left.val + right_str := (cond.right as ast.StringLiteral).val + if cond.op == .eq { + is_true = left_str == right_str + } else if cond.op == .ne { + is_true = left_str != right_str + } else { + c.error('string type only support `==` and `!=` operator', + cond.pos) + return false, false + } + sb.write_string('${is_true}') + return is_true, false + } ast.Ident { // $if version == 2 left_type := c.expr(mut cond.left) diff --git a/vlib/v/checker/match.v b/vlib/v/checker/match.v index 90780494c1..6d3530d00d 100644 --- a/vlib/v/checker/match.v +++ b/vlib/v/checker/match.v @@ -20,11 +20,15 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type { } mut cond_type := ast.void_type if node.is_comptime { - // for field.name and generic type `T` - if node.cond is ast.SelectorExpr { - c.expr(mut node.cond) + if node.cond is ast.AtExpr { + cond_type = c.expr(mut node.cond) + } else { + // for field.name and generic type `T` + if node.cond is ast.SelectorExpr { + c.expr(mut node.cond) + } + cond_type = c.get_expr_type(node.cond) } - cond_type = c.get_expr_type(node.cond) } else { cond_type = c.expr(mut node.cond) } @@ -69,7 +73,7 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type { c.expr(mut node.cond) if !c.type_resolver.is_generic_param_var(node.cond) { match mut node.cond { - ast.StringLiteral { + ast.StringLiteral, ast.AtExpr { comptime_match_cond_value = node.cond.val } ast.IntegerLiteral { diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 210e8d80df..c1e0368510 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -1001,6 +1001,16 @@ pub fn (mut g Gen) init() { } else { g.cheaders.writeln(c_headers) } + if !g.pref.skip_unused || g.table.used_features.used_attr_weak { + g.cheaders.writeln(c_common_weak_attr) + } + if !g.pref.skip_unused || g.table.used_features.used_attr_hidden { + g.cheaders.writeln(c_common_hidden_attr) + } + if !g.pref.skip_unused || g.table.used_features.used_attr_noreturn { + g.cheaders.writeln(c_common_noreturn_attr) + g.cheaders.writeln(c_common_unreachable_attr) + } if !g.pref.skip_unused || g.table.used_features.used_maps > 0 { g.cheaders.writeln(c_wyhash_headers) } diff --git a/vlib/v/gen/c/cheaders.v b/vlib/v/gen/c/cheaders.v index 554086db64..50718595f0 100644 --- a/vlib/v/gen/c/cheaders.v +++ b/vlib/v/gen/c/cheaders.v @@ -180,8 +180,6 @@ const c_common_macros = ' #endif #endif -#define OPTION_CAST(x) (x) - #if defined(_WIN32) || defined(__CYGWIN__) #define VV_EXP extern __declspec(dllexport) #define VV_LOC static @@ -220,7 +218,17 @@ const c_common_macros = ' #undef __has_include #endif +//likely and unlikely macros +#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__) + #define _likely_(x) __builtin_expect(x,1) + #define _unlikely_(x) __builtin_expect(x,0) +#else + #define _likely_(x) (x) + #define _unlikely_(x) (x) +#endif +' +const c_common_weak_attr = ' #if !defined(VWEAK) #define VWEAK __attribute__((weak)) #ifdef _MSC_VER @@ -232,7 +240,9 @@ const c_common_macros = ' #define VWEAK #endif #endif +' +const c_common_hidden_attr = ' #if !defined(VHIDDEN) #define VHIDDEN __attribute__((visibility("hidden"))) #ifdef _MSC_VER @@ -244,7 +254,9 @@ const c_common_macros = ' #define VHIDDEN #endif #endif +' +const c_common_noreturn_attr = ' #if !defined(VNORETURN) #if defined(__TINYC__) #include @@ -259,7 +271,9 @@ const c_common_macros = ' #define VNORETURN #endif #endif +' +const c_common_unreachable_attr = ' #if !defined(VUNREACHABLE) #if defined(__GNUC__) && !defined(__clang__) #define V_GCC_VERSION (__GNUC__ * 10000L + __GNUC_MINOR__ * 100L + __GNUC_PATCHLEVEL__) @@ -276,16 +290,6 @@ const c_common_macros = ' #define VUNREACHABLE() do { } while (0) #endif #endif - -//likely and unlikely macros -#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__) - #define _likely_(x) __builtin_expect(x,1) - #define _unlikely_(x) __builtin_expect(x,0) -#else - #define _likely_(x) (x) - #define _unlikely_(x) (x) -#endif - ' const c_unsigned_comparison_functions = ' @@ -433,8 +437,6 @@ void v_free(voidptr ptr); #define _Atomic volatile // MSVC cannot parse some things properly - #undef OPTION_CAST - #define OPTION_CAST(x) #undef __NOINLINE #undef __IRQHANDLER #define __NOINLINE __declspec(noinline) @@ -451,9 +453,6 @@ void v_free(voidptr ptr); #endif #endif -// g_live_info is used by live.info() -static void* g_live_info = NULL; - #if defined(__MINGW32__) || defined(__MINGW64__) || (defined(_WIN32) && defined(__TINYC__)) #undef PRId64 #undef PRIi64 @@ -711,5 +710,4 @@ static inline uint64_t wy2u0k(uint64_t r, uint64_t k){ _wymum(&r,&k); return k; #endif #define _IN_MAP(val, m) map_exists(m, val) - ' diff --git a/vlib/v/gen/c/consts_and_globals.v b/vlib/v/gen/c/consts_and_globals.v index cf9f0042be..756843cfb0 100644 --- a/vlib/v/gen/c/consts_and_globals.v +++ b/vlib/v/gen/c/consts_and_globals.v @@ -437,13 +437,14 @@ fn (mut g Gen) global_decl(node ast.GlobalDecl) { should_init := (!g.pref.use_cache && g.pref.build_mode != .build_module) || (g.pref.build_mode == .build_module && g.module_built == node.mod) mut attributes := '' - if node.attrs.contains('weak') { + first_field := node.fields[0] + if first_field.is_weak { attributes += 'VWEAK ' } - if node.attrs.contains('hidden') { + if first_field.is_hidden { attributes += 'VHIDDEN ' } - if node.attrs.contains('export') { + if first_field.is_exported { attributes += 'VV_EXP ' } if attr := node.attrs.find_first('_linker_section') { diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 34a0835e70..f371e032ea 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -532,9 +532,9 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) { if g.pref.printfn_list.len > 0 && g.last_fn_c_name in g.pref.printfn_list { println(g.out.after(fn_start_pos)) } + weak := if node.is_weak { 'VWEAK ' } else { '' } for attr in node.attrs { if attr.name == 'export' { - weak := if node.attrs.any(it.name == 'weak') { 'VWEAK ' } else { '' } g.writeln('// export alias: ${attr.arg} -> ${name}') g.export_funcs << attr.arg export_alias := '${weak}${type_name} ${fn_attrs}${attr.arg}(${arg_str})' diff --git a/vlib/v/markused/walker.v b/vlib/v/markused/walker.v index f378d4244f..ecbf77fe99 100644 --- a/vlib/v/markused/walker.v +++ b/vlib/v/markused/walker.v @@ -142,6 +142,9 @@ pub fn (mut w Walker) mark_global_as_used(ckey string) { } w.used_globals[ckey] = true gfield := w.all_globals[ckey] or { return } + w.table.used_features.used_attr_weak = w.table.used_features.used_attr_weak || gfield.is_weak + w.table.used_features.used_attr_hidden = w.table.used_features.used_attr_hidden + || gfield.is_hidden || gfield.is_hidden w.expr(gfield.expr) if !gfield.has_expr { w.mark_by_type(gfield.typ) @@ -355,9 +358,7 @@ pub fn (mut w Walker) stmt(node_ ast.Stmt) { w.mark_by_type(typ.typ) } w.struct_fields(node.fields) - if !w.uses_mem_align { - w.uses_mem_align = node.attrs.contains('aligned') - } + w.uses_mem_align = w.uses_mem_align || node.is_aligned } ast.DeferStmt { w.stmts(node.stmts) @@ -894,6 +895,9 @@ pub fn (mut w Walker) fn_decl(mut node ast.FnDecl) { w.is_builtin_mod = last_is_builtin_mod } } + w.table.used_features.used_attr_weak = w.table.used_features.used_attr_weak || node.is_weak + w.table.used_features.used_attr_noreturn = w.table.used_features.used_attr_noreturn + || node.is_noreturn if node.language == .c { w.mark_fn_as_used(node.fkey()) w.mark_fn_ret_and_params(node.return_type, node.params) @@ -1153,9 +1157,7 @@ pub fn (mut w Walker) mark_by_sym(isym ast.TypeSymbol) { } if decl := w.all_structs[isym.name] { w.struct_fields(decl.fields) - if !w.uses_mem_align { - w.uses_mem_align = decl.attrs.contains('aligned') - } + w.uses_mem_align = w.uses_mem_align || decl.is_aligned for iface_typ in decl.implements_types { w.mark_by_type(iface_typ.typ) } diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 8dd3ac1594..96403cdf5f 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -213,6 +213,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { mut is_c2v_variadic := false mut is_c_extern := false mut is_markused := false + mut is_weak := false mut is_expand_simple_interpolation := false mut comments := []ast.Comment{} fn_attrs := p.attrs @@ -254,6 +255,9 @@ fn (mut p Parser) fn_decl() ast.FnDecl { 'c2v_variadic' { is_c2v_variadic = true } + 'weak' { + is_weak = true + } 'use_new' { is_ctor_new = true } @@ -706,6 +710,7 @@ run them via `v file.v` instead', is_unsafe: is_unsafe is_must_use: is_must_use is_markused: is_markused + is_weak: is_weak is_file_translated: p.is_translated // attrs: fn_attrs diff --git a/vlib/v/parser/if_match.v b/vlib/v/parser/if_match.v index 260be280f4..c5e008c98d 100644 --- a/vlib/v/parser/if_match.v +++ b/vlib/v/parser/if_match.v @@ -6,6 +6,7 @@ module parser import v.ast import v.token import v.pkgconfig +import v.pref fn (mut p Parser) if_expr(is_comptime bool, is_expr bool) ast.IfExpr { was_inside_if_expr := p.inside_if_expr @@ -193,7 +194,9 @@ fn (mut p Parser) if_expr(is_comptime bool, is_expr bool) ast.IfExpr { return ast.IfExpr{} } p.open_scope() - if is_comptime && comptime_skip_curr_stmts && !p.pref.is_fmt && !p.pref.output_cross_c { + if is_comptime && comptime_skip_curr_stmts + && p.is_in_top_level_comptime(p.inside_assign_rhs) && !p.pref.is_fmt + && !p.pref.output_cross_c { p.skip_scope() branches << ast.IfBranch{ cond: cond @@ -278,29 +281,64 @@ fn (mut p Parser) is_match_sumtype_type() bool { && next_next_tok.lit.len > 0 && next_next_tok.lit[0].is_capital())) } +fn (mut p Parser) resolve_at_expr(expr ast.AtExpr) !string { + match expr.kind { + .mod_name { + return p.mod + } + .os { + return pref.get_host_os().lower() + } + .ccompiler { + return p.pref.ccompiler_type.str() + } + .backend { + return p.pref.backend.str() + } + .platform { + return p.pref.arch.str() + } + else { + return error('top level comptime only support `@MOD` `@OS` `@CCOMPILER` `@BACKEND` or `@PLATFORM`') + } + } + return '' +} + fn (mut p Parser) match_expr(is_comptime bool) ast.MatchExpr { mut match_first_pos := p.tok.pos() + old_inside_ct_match := p.inside_ct_match if is_comptime { p.next() // `$` match_first_pos = p.prev_tok.pos().extend(p.tok.pos()) + p.inside_ct_match = true } old_inside_match := p.inside_match p.inside_match = true p.check(.key_match) mut is_sum_type := false cond := p.expr(0) + mut cond_str := '' + if is_comptime && cond is ast.AtExpr && p.is_in_top_level_comptime(p.inside_assign_rhs) { + cond_str = p.resolve_at_expr(cond) or { + p.error(err.msg()) + return ast.MatchExpr{} + } + } p.inside_match = old_inside_match + p.inside_ct_match = old_inside_ct_match no_lcbr := p.tok.kind != .lcbr if !no_lcbr { p.check(.lcbr) } comments := p.eat_comments() // comments before the first branch mut branches := []ast.MatchBranch{} + mut comptime_skip_curr_stmts := false + mut comptime_has_true_branch := false for p.tok.kind != .eof { branch_first_pos := p.tok.pos() mut exprs := []ast.Expr{} mut ecmnts := [][]ast.Comment{} - p.open_scope() // final else mut is_else := false if is_comptime { @@ -352,19 +390,44 @@ fn (mut p Parser) match_expr(is_comptime bool) ast.MatchExpr { } // Expression match for { + if is_comptime { + p.inside_ct_match_case = true + } p.inside_match_case = true mut range_pos := p.tok.pos() - expr := p.expr(0) + mut case_str := '' + mut expr := p.expr(0) p.inside_match_case = false + p.inside_ct_match_case = false + match mut expr { + ast.StringLiteral { + case_str = expr.val + } + ast.IntegerLiteral { + case_str = expr.val.str() + } + ast.BoolLiteral { + case_str = expr.val.str() + } + else {} + } + comptime_skip_curr_stmts = cond_str != case_str + if !comptime_skip_curr_stmts { + comptime_has_true_branch = true + } if p.tok.kind == .dotdot { p.error_with_pos('match only supports inclusive (`...`) ranges, not exclusive (`..`)', p.tok.pos()) return ast.MatchExpr{} } else if p.tok.kind == .ellipsis { p.next() + if is_comptime { + p.inside_ct_match_case = true + } p.inside_match_case = true expr2 := p.expr(0) p.inside_match_case = false + p.inside_ct_match_case = false exprs << ast.RangeExpr{ low: expr high: expr2 @@ -394,11 +457,24 @@ fn (mut p Parser) match_expr(is_comptime bool) ast.MatchExpr { } branch_last_pos := p.prev_tok.pos() // p.warn('match block') + if is_comptime { + p.inside_ct_match_body = true + } p.inside_match_body = true - stmts := p.parse_block_no_scope(false) + p.open_scope() + mut stmts := []ast.Stmt{} + if is_comptime && ((!is_else && comptime_skip_curr_stmts) + || (is_else && comptime_has_true_branch)) + && p.is_in_top_level_comptime(p.inside_assign_rhs) && !p.pref.is_fmt + && !p.pref.output_cross_c { + p.skip_scope() + } else { + stmts = p.parse_block_no_scope(false) + } branch_scope := p.scope p.close_scope() p.inside_match_body = false + p.inside_ct_match_body = false pos := branch_first_pos.extend_with_last_line(branch_last_pos, p.prev_tok.line_nr) branch_pos := branch_first_pos.extend_with_last_line(p.tok.pos(), p.tok.line_nr) post_comments := p.eat_comments() @@ -643,6 +719,27 @@ fn (mut p Parser) comptime_if_cond(mut cond ast.Expr) bool { } .eq, .ne, .gt, .lt, .ge, .le { match mut cond.left { + ast.AtExpr { + // @OS == 'linux' + left_str := p.resolve_at_expr(cond.left) or { + p.error(err.msg()) + return false + } + if cond.right !is ast.StringLiteral { + p.error('`${cond.left} can only compare with string type') + return false + } + right_str := (cond.right as ast.StringLiteral).val + if cond.op == .eq { + is_true = left_str == right_str + } else if cond.op == .ne { + is_true = left_str != right_str + } else { + p.error('string type only support `==` and `!=` operator') + return false + } + return is_true + } ast.Ident { // $if version == 2 match mut cond.right { diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 20abc5cc64..c762ce7f10 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -53,6 +53,9 @@ mut: inside_select bool // to allow `ch <- Struct{} {` inside `select` inside_match_case bool // to separate `match_expr { }` from `Struct{}` inside_match_body bool // to fix eval not used TODO + inside_ct_match bool + inside_ct_match_case bool + inside_ct_match_body bool inside_unsafe bool inside_sum_type bool // to prevent parsing inline sum type again inside_asm_template bool @@ -455,8 +458,9 @@ fn (mut p Parser) parse_block() []ast.Stmt { 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 + return p.cur_fn_name.len == 0 + && (p.inside_ct_if_expr || p.inside_ct_match || p.inside_ct_match_body) + && !inside_assign_rhs && !p.script_mode && p.tok.kind != .name } fn (mut p Parser) parse_block_no_scope(is_top_level bool) []ast.Stmt { @@ -2599,10 +2603,14 @@ fn (mut p Parser) global_decl() ast.GlobalDecl { mut is_markused := false mut is_exported := false + mut is_weak := false + mut is_hidden := false for ga in attrs { match ga.name { 'export' { is_exported = true } 'markused' { is_markused = true } + 'weak' { is_weak = true } + 'hidden' { is_hidden = true } else {} } } @@ -2687,6 +2695,8 @@ fn (mut p Parser) global_decl() ast.GlobalDecl { is_markused: is_markused is_volatile: is_volatile is_exported: is_exported + is_weak: is_weak + is_hidden: is_hidden } fields << field if name !in ast.global_reserved_type_names { diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v index 87a8b560d0..dc136d84c1 100644 --- a/vlib/v/parser/struct.v +++ b/vlib/v/parser/struct.v @@ -480,6 +480,7 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl { language: language is_union: is_union is_option: is_option + is_aligned: attrs.contains('aligned') attrs: if is_anon { []ast.Attr{} } else { attrs } // anon structs can't have attributes pre_comments: pre_comments end_comments: end_comments diff --git a/vlib/v/tests/comptime/comptime_if_at_expr_test.v b/vlib/v/tests/comptime/comptime_if_at_expr_test.v new file mode 100644 index 0000000000..91e91cad87 --- /dev/null +++ b/vlib/v/tests/comptime/comptime_if_at_expr_test.v @@ -0,0 +1,34 @@ +module main + +$if @MOD == 'main' { + const c1 = 'main' +} $else { + const c1 = 'other' +} + +$if @OS == 'linux' { + const os = 'linux' +} $else $if @OS == 'windows' { + const os = 'windows' +} $else { + const os = 'other' +} + +fn test_comptime_if_at_expr() { + assert c1 == 'main' + + $if linux { + assert os == 'linux' + } $else $if windows { + assert os == 'windows' + } $else { + assert os == 'other' + } + + dump(@FN) + $if @FN == 'test_comptime_if_at_expr' { + assert true + } $else { + assert false + } +} diff --git a/vlib/v/tests/comptime/comptime_match_at_expr_test.v b/vlib/v/tests/comptime/comptime_match_at_expr_test.v new file mode 100644 index 0000000000..6dc665bcc3 --- /dev/null +++ b/vlib/v/tests/comptime/comptime_match_at_expr_test.v @@ -0,0 +1,44 @@ +module main + +$match @MOD { + 'main' { + const c1 = 'main' + } + $else { + const c1 = 'other' + } +} + +$match @OS { + 'linux' { + const os = 'linux' + } + 'windows' { + const os = 'windows' + } + $else { + const os = 'other' + } +} + +fn test_comptime_match_at_expr() { + assert c1 == 'main' + + dump(@FN) + $match @FN { + 'test_comptime_match_at_expr' { + assert true + } + $else { + assert false + } + } + + $if linux { + assert os == 'linux' + } $else $if windows { + assert os == 'windows' + } $else { + assert os == 'other' + } +}