mirror of
https://github.com/vlang/v.git
synced 2025-09-13 14:32:26 +03:00
Compare commits
3 commits
19d31f221f
...
f6b60e4d9f
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f6b60e4d9f | ||
![]() |
2e8cc75e5f | ||
![]() |
840e659d08 |
17 changed files with 290 additions and 44 deletions
|
@ -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_terse('is_variadic', t.bool_node(node.is_variadic))
|
||||||
obj.add('is_anon', t.bool_node(node.is_anon))
|
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_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_terse('is_manualfree', t.bool_node(node.is_manualfree))
|
||||||
obj.add('is_main', t.bool_node(node.is_main))
|
obj.add('is_main', t.bool_node(node.is_main))
|
||||||
obj.add('is_test', t.bool_node(node.is_test))
|
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('typ', t.type_node(node.typ))
|
||||||
obj.add_terse('has_expr', t.bool_node(node.has_expr))
|
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_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('comments', t.array_node_comment(node.comments))
|
||||||
obj.add('pos', t.pos(node.pos))
|
obj.add('pos', t.pos(node.pos))
|
||||||
obj.add('typ_pos', t.pos(node.typ_pos))
|
obj.add('typ_pos', t.pos(node.typ_pos))
|
||||||
|
|
|
@ -10,6 +10,7 @@ module readline
|
||||||
import term.termios
|
import term.termios
|
||||||
import term
|
import term
|
||||||
import os
|
import os
|
||||||
|
import encoding.utf8.east_asian
|
||||||
|
|
||||||
fn C.raise(sig int)
|
fn C.raise(sig int)
|
||||||
|
|
||||||
|
@ -379,12 +380,16 @@ fn (mut r Readline) refresh_line() {
|
||||||
} else {
|
} else {
|
||||||
r.prompt
|
r.prompt
|
||||||
}
|
}
|
||||||
end_of_input = calculate_screen_position(last_prompt_line.len, 0, get_screen_columns(),
|
last_prompt_width := east_asian.display_width(last_prompt_line, 1)
|
||||||
r.current.len, end_of_input)
|
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
|
end_of_input[1] += r.current.filter(it == `\n`).len
|
||||||
mut cursor_pos := [0, 0]
|
mut cursor_pos := [0, 0]
|
||||||
cursor_pos = calculate_screen_position(last_prompt_line.len, 0, get_screen_columns(),
|
cursor_pos = calculate_screen_position(last_prompt_width, 0, get_screen_columns(),
|
||||||
r.cursor, cursor_pos)
|
cursor_prefix_width, cursor_pos)
|
||||||
shift_cursor(0, -r.cursor_row_offset)
|
shift_cursor(0, -r.cursor_row_offset)
|
||||||
term.erase_toend()
|
term.erase_toend()
|
||||||
print(last_prompt_line)
|
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 {
|
if end_of_input[0] == 0 && end_of_input[1] > 0 {
|
||||||
print('\n')
|
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]
|
r.cursor_row_offset = cursor_pos[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -446,6 +446,7 @@ pub:
|
||||||
module_pos int = -1 // module:
|
module_pos int = -1 // module:
|
||||||
is_union bool
|
is_union bool
|
||||||
is_option bool
|
is_option bool
|
||||||
|
is_aligned bool
|
||||||
attrs []Attr
|
attrs []Attr
|
||||||
pre_comments []Comment
|
pre_comments []Comment
|
||||||
end_comments []Comment
|
end_comments []Comment
|
||||||
|
@ -593,6 +594,7 @@ pub:
|
||||||
is_c_extern bool
|
is_c_extern bool
|
||||||
is_variadic bool
|
is_variadic bool
|
||||||
is_anon bool
|
is_anon bool
|
||||||
|
is_weak bool
|
||||||
is_noreturn bool // true, when @[noreturn] is used on a fn
|
is_noreturn bool // true, when @[noreturn] is used on a fn
|
||||||
is_manualfree bool // true, when @[manualfree] is used on a fn
|
is_manualfree bool // true, when @[manualfree] is used on a fn
|
||||||
is_main bool // true for `fn main()`
|
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_markused bool // an explicit `@[markused]` tag; the global will NOT be removed by `-skip-unused`
|
||||||
is_volatile bool
|
is_volatile bool
|
||||||
is_exported bool // an explicit `@[export]` tag; the global will NOT be removed by `-skip-unused`
|
is_exported bool // an explicit `@[export]` tag; the global will NOT be removed by `-skip-unused`
|
||||||
|
is_weak bool
|
||||||
|
is_hidden bool
|
||||||
pub mut:
|
pub mut:
|
||||||
expr Expr
|
expr Expr
|
||||||
typ Type
|
typ Type
|
||||||
|
|
|
@ -38,6 +38,10 @@ pub mut:
|
||||||
// json bool // json is imported
|
// json bool // json is imported
|
||||||
comptime_calls map[string]bool // resolved name to call on comptime
|
comptime_calls map[string]bool // resolved name to call on comptime
|
||||||
comptime_syms map[Type]bool // resolved syms (generic)
|
comptime_syms map[Type]bool // resolved syms (generic)
|
||||||
|
//
|
||||||
|
used_attr_noreturn bool // @[noreturn]
|
||||||
|
used_attr_hidden bool // @[hidden]
|
||||||
|
used_attr_weak bool // @[weak]
|
||||||
}
|
}
|
||||||
|
|
||||||
@[unsafe]
|
@[unsafe]
|
||||||
|
|
|
@ -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 {
|
.eq, .ne, .gt, .lt, .ge, .le {
|
||||||
match mut cond.left {
|
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 {
|
ast.Ident {
|
||||||
// $if version == 2
|
// $if version == 2
|
||||||
left_type := c.expr(mut cond.left)
|
left_type := c.expr(mut cond.left)
|
||||||
|
|
|
@ -20,11 +20,15 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
|
||||||
}
|
}
|
||||||
mut cond_type := ast.void_type
|
mut cond_type := ast.void_type
|
||||||
if node.is_comptime {
|
if node.is_comptime {
|
||||||
// for field.name and generic type `T`
|
if node.cond is ast.AtExpr {
|
||||||
if node.cond is ast.SelectorExpr {
|
cond_type = c.expr(mut node.cond)
|
||||||
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 {
|
} else {
|
||||||
cond_type = c.expr(mut node.cond)
|
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)
|
c.expr(mut node.cond)
|
||||||
if !c.type_resolver.is_generic_param_var(node.cond) {
|
if !c.type_resolver.is_generic_param_var(node.cond) {
|
||||||
match mut node.cond {
|
match mut node.cond {
|
||||||
ast.StringLiteral {
|
ast.StringLiteral, ast.AtExpr {
|
||||||
comptime_match_cond_value = node.cond.val
|
comptime_match_cond_value = node.cond.val
|
||||||
}
|
}
|
||||||
ast.IntegerLiteral {
|
ast.IntegerLiteral {
|
||||||
|
|
|
@ -1001,6 +1001,16 @@ pub fn (mut g Gen) init() {
|
||||||
} else {
|
} else {
|
||||||
g.cheaders.writeln(c_headers)
|
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 {
|
if !g.pref.skip_unused || g.table.used_features.used_maps > 0 {
|
||||||
g.cheaders.writeln(c_wyhash_headers)
|
g.cheaders.writeln(c_wyhash_headers)
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,8 +180,6 @@ const c_common_macros = '
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define OPTION_CAST(x) (x)
|
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||||
#define VV_EXP extern __declspec(dllexport)
|
#define VV_EXP extern __declspec(dllexport)
|
||||||
#define VV_LOC static
|
#define VV_LOC static
|
||||||
|
@ -220,7 +218,17 @@ const c_common_macros = '
|
||||||
#undef __has_include
|
#undef __has_include
|
||||||
#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_common_weak_attr = '
|
||||||
#if !defined(VWEAK)
|
#if !defined(VWEAK)
|
||||||
#define VWEAK __attribute__((weak))
|
#define VWEAK __attribute__((weak))
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
@ -232,7 +240,9 @@ const c_common_macros = '
|
||||||
#define VWEAK
|
#define VWEAK
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
'
|
||||||
|
|
||||||
|
const c_common_hidden_attr = '
|
||||||
#if !defined(VHIDDEN)
|
#if !defined(VHIDDEN)
|
||||||
#define VHIDDEN __attribute__((visibility("hidden")))
|
#define VHIDDEN __attribute__((visibility("hidden")))
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
@ -244,7 +254,9 @@ const c_common_macros = '
|
||||||
#define VHIDDEN
|
#define VHIDDEN
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
'
|
||||||
|
|
||||||
|
const c_common_noreturn_attr = '
|
||||||
#if !defined(VNORETURN)
|
#if !defined(VNORETURN)
|
||||||
#if defined(__TINYC__)
|
#if defined(__TINYC__)
|
||||||
#include <stdnoreturn.h>
|
#include <stdnoreturn.h>
|
||||||
|
@ -259,7 +271,9 @@ const c_common_macros = '
|
||||||
#define VNORETURN
|
#define VNORETURN
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
'
|
||||||
|
|
||||||
|
const c_common_unreachable_attr = '
|
||||||
#if !defined(VUNREACHABLE)
|
#if !defined(VUNREACHABLE)
|
||||||
#if defined(__GNUC__) && !defined(__clang__)
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
#define V_GCC_VERSION (__GNUC__ * 10000L + __GNUC_MINOR__ * 100L + __GNUC_PATCHLEVEL__)
|
#define V_GCC_VERSION (__GNUC__ * 10000L + __GNUC_MINOR__ * 100L + __GNUC_PATCHLEVEL__)
|
||||||
|
@ -276,16 +290,6 @@ const c_common_macros = '
|
||||||
#define VUNREACHABLE() do { } while (0)
|
#define VUNREACHABLE() do { } while (0)
|
||||||
#endif
|
#endif
|
||||||
#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 = '
|
const c_unsigned_comparison_functions = '
|
||||||
|
@ -433,8 +437,6 @@ void v_free(voidptr ptr);
|
||||||
#define _Atomic volatile
|
#define _Atomic volatile
|
||||||
|
|
||||||
// MSVC cannot parse some things properly
|
// MSVC cannot parse some things properly
|
||||||
#undef OPTION_CAST
|
|
||||||
#define OPTION_CAST(x)
|
|
||||||
#undef __NOINLINE
|
#undef __NOINLINE
|
||||||
#undef __IRQHANDLER
|
#undef __IRQHANDLER
|
||||||
#define __NOINLINE __declspec(noinline)
|
#define __NOINLINE __declspec(noinline)
|
||||||
|
@ -451,9 +453,6 @@ void v_free(voidptr ptr);
|
||||||
#endif
|
#endif
|
||||||
#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__))
|
#if defined(__MINGW32__) || defined(__MINGW64__) || (defined(_WIN32) && defined(__TINYC__))
|
||||||
#undef PRId64
|
#undef PRId64
|
||||||
#undef PRIi64
|
#undef PRIi64
|
||||||
|
@ -711,5 +710,4 @@ static inline uint64_t wy2u0k(uint64_t r, uint64_t k){ _wymum(&r,&k); return k;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define _IN_MAP(val, m) map_exists(m, val)
|
#define _IN_MAP(val, m) map_exists(m, val)
|
||||||
|
|
||||||
'
|
'
|
||||||
|
|
|
@ -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)
|
should_init := (!g.pref.use_cache && g.pref.build_mode != .build_module)
|
||||||
|| (g.pref.build_mode == .build_module && g.module_built == node.mod)
|
|| (g.pref.build_mode == .build_module && g.module_built == node.mod)
|
||||||
mut attributes := ''
|
mut attributes := ''
|
||||||
if node.attrs.contains('weak') {
|
first_field := node.fields[0]
|
||||||
|
if first_field.is_weak {
|
||||||
attributes += 'VWEAK '
|
attributes += 'VWEAK '
|
||||||
}
|
}
|
||||||
if node.attrs.contains('hidden') {
|
if first_field.is_hidden {
|
||||||
attributes += 'VHIDDEN '
|
attributes += 'VHIDDEN '
|
||||||
}
|
}
|
||||||
if node.attrs.contains('export') {
|
if first_field.is_exported {
|
||||||
attributes += 'VV_EXP '
|
attributes += 'VV_EXP '
|
||||||
}
|
}
|
||||||
if attr := node.attrs.find_first('_linker_section') {
|
if attr := node.attrs.find_first('_linker_section') {
|
||||||
|
|
|
@ -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 {
|
if g.pref.printfn_list.len > 0 && g.last_fn_c_name in g.pref.printfn_list {
|
||||||
println(g.out.after(fn_start_pos))
|
println(g.out.after(fn_start_pos))
|
||||||
}
|
}
|
||||||
|
weak := if node.is_weak { 'VWEAK ' } else { '' }
|
||||||
for attr in node.attrs {
|
for attr in node.attrs {
|
||||||
if attr.name == 'export' {
|
if attr.name == 'export' {
|
||||||
weak := if node.attrs.any(it.name == 'weak') { 'VWEAK ' } else { '' }
|
|
||||||
g.writeln('// export alias: ${attr.arg} -> ${name}')
|
g.writeln('// export alias: ${attr.arg} -> ${name}')
|
||||||
g.export_funcs << attr.arg
|
g.export_funcs << attr.arg
|
||||||
export_alias := '${weak}${type_name} ${fn_attrs}${attr.arg}(${arg_str})'
|
export_alias := '${weak}${type_name} ${fn_attrs}${attr.arg}(${arg_str})'
|
||||||
|
|
|
@ -142,6 +142,9 @@ pub fn (mut w Walker) mark_global_as_used(ckey string) {
|
||||||
}
|
}
|
||||||
w.used_globals[ckey] = true
|
w.used_globals[ckey] = true
|
||||||
gfield := w.all_globals[ckey] or { return }
|
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)
|
w.expr(gfield.expr)
|
||||||
if !gfield.has_expr {
|
if !gfield.has_expr {
|
||||||
w.mark_by_type(gfield.typ)
|
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.mark_by_type(typ.typ)
|
||||||
}
|
}
|
||||||
w.struct_fields(node.fields)
|
w.struct_fields(node.fields)
|
||||||
if !w.uses_mem_align {
|
w.uses_mem_align = w.uses_mem_align || node.is_aligned
|
||||||
w.uses_mem_align = node.attrs.contains('aligned')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ast.DeferStmt {
|
ast.DeferStmt {
|
||||||
w.stmts(node.stmts)
|
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.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 {
|
if node.language == .c {
|
||||||
w.mark_fn_as_used(node.fkey())
|
w.mark_fn_as_used(node.fkey())
|
||||||
w.mark_fn_ret_and_params(node.return_type, node.params)
|
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] {
|
if decl := w.all_structs[isym.name] {
|
||||||
w.struct_fields(decl.fields)
|
w.struct_fields(decl.fields)
|
||||||
if !w.uses_mem_align {
|
w.uses_mem_align = w.uses_mem_align || decl.is_aligned
|
||||||
w.uses_mem_align = decl.attrs.contains('aligned')
|
|
||||||
}
|
|
||||||
for iface_typ in decl.implements_types {
|
for iface_typ in decl.implements_types {
|
||||||
w.mark_by_type(iface_typ.typ)
|
w.mark_by_type(iface_typ.typ)
|
||||||
}
|
}
|
||||||
|
|
|
@ -213,6 +213,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||||
mut is_c2v_variadic := false
|
mut is_c2v_variadic := false
|
||||||
mut is_c_extern := false
|
mut is_c_extern := false
|
||||||
mut is_markused := false
|
mut is_markused := false
|
||||||
|
mut is_weak := false
|
||||||
mut is_expand_simple_interpolation := false
|
mut is_expand_simple_interpolation := false
|
||||||
mut comments := []ast.Comment{}
|
mut comments := []ast.Comment{}
|
||||||
fn_attrs := p.attrs
|
fn_attrs := p.attrs
|
||||||
|
@ -254,6 +255,9 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||||
'c2v_variadic' {
|
'c2v_variadic' {
|
||||||
is_c2v_variadic = true
|
is_c2v_variadic = true
|
||||||
}
|
}
|
||||||
|
'weak' {
|
||||||
|
is_weak = true
|
||||||
|
}
|
||||||
'use_new' {
|
'use_new' {
|
||||||
is_ctor_new = true
|
is_ctor_new = true
|
||||||
}
|
}
|
||||||
|
@ -706,6 +710,7 @@ run them via `v file.v` instead',
|
||||||
is_unsafe: is_unsafe
|
is_unsafe: is_unsafe
|
||||||
is_must_use: is_must_use
|
is_must_use: is_must_use
|
||||||
is_markused: is_markused
|
is_markused: is_markused
|
||||||
|
is_weak: is_weak
|
||||||
is_file_translated: p.is_translated
|
is_file_translated: p.is_translated
|
||||||
//
|
//
|
||||||
attrs: fn_attrs
|
attrs: fn_attrs
|
||||||
|
|
|
@ -6,6 +6,7 @@ module parser
|
||||||
import v.ast
|
import v.ast
|
||||||
import v.token
|
import v.token
|
||||||
import v.pkgconfig
|
import v.pkgconfig
|
||||||
|
import v.pref
|
||||||
|
|
||||||
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
|
||||||
|
@ -193,7 +194,9 @@ 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 {
|
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()
|
p.skip_scope()
|
||||||
branches << ast.IfBranch{
|
branches << ast.IfBranch{
|
||||||
cond: cond
|
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()))
|
&& 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 {
|
fn (mut p Parser) match_expr(is_comptime bool) ast.MatchExpr {
|
||||||
mut match_first_pos := p.tok.pos()
|
mut match_first_pos := p.tok.pos()
|
||||||
|
old_inside_ct_match := p.inside_ct_match
|
||||||
if is_comptime {
|
if is_comptime {
|
||||||
p.next() // `$`
|
p.next() // `$`
|
||||||
match_first_pos = p.prev_tok.pos().extend(p.tok.pos())
|
match_first_pos = p.prev_tok.pos().extend(p.tok.pos())
|
||||||
|
p.inside_ct_match = true
|
||||||
}
|
}
|
||||||
old_inside_match := p.inside_match
|
old_inside_match := p.inside_match
|
||||||
p.inside_match = true
|
p.inside_match = true
|
||||||
p.check(.key_match)
|
p.check(.key_match)
|
||||||
mut is_sum_type := false
|
mut is_sum_type := false
|
||||||
cond := p.expr(0)
|
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_match = old_inside_match
|
||||||
|
p.inside_ct_match = old_inside_ct_match
|
||||||
no_lcbr := p.tok.kind != .lcbr
|
no_lcbr := p.tok.kind != .lcbr
|
||||||
if !no_lcbr {
|
if !no_lcbr {
|
||||||
p.check(.lcbr)
|
p.check(.lcbr)
|
||||||
}
|
}
|
||||||
comments := p.eat_comments() // comments before the first branch
|
comments := p.eat_comments() // comments before the first branch
|
||||||
mut branches := []ast.MatchBranch{}
|
mut branches := []ast.MatchBranch{}
|
||||||
|
mut comptime_skip_curr_stmts := false
|
||||||
|
mut comptime_has_true_branch := false
|
||||||
for p.tok.kind != .eof {
|
for p.tok.kind != .eof {
|
||||||
branch_first_pos := p.tok.pos()
|
branch_first_pos := p.tok.pos()
|
||||||
mut exprs := []ast.Expr{}
|
mut exprs := []ast.Expr{}
|
||||||
mut ecmnts := [][]ast.Comment{}
|
mut ecmnts := [][]ast.Comment{}
|
||||||
p.open_scope()
|
|
||||||
// final else
|
// final else
|
||||||
mut is_else := false
|
mut is_else := false
|
||||||
if is_comptime {
|
if is_comptime {
|
||||||
|
@ -352,19 +390,44 @@ fn (mut p Parser) match_expr(is_comptime bool) ast.MatchExpr {
|
||||||
}
|
}
|
||||||
// Expression match
|
// Expression match
|
||||||
for {
|
for {
|
||||||
|
if is_comptime {
|
||||||
|
p.inside_ct_match_case = true
|
||||||
|
}
|
||||||
p.inside_match_case = true
|
p.inside_match_case = true
|
||||||
mut range_pos := p.tok.pos()
|
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_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 {
|
if p.tok.kind == .dotdot {
|
||||||
p.error_with_pos('match only supports inclusive (`...`) ranges, not exclusive (`..`)',
|
p.error_with_pos('match only supports inclusive (`...`) ranges, not exclusive (`..`)',
|
||||||
p.tok.pos())
|
p.tok.pos())
|
||||||
return ast.MatchExpr{}
|
return ast.MatchExpr{}
|
||||||
} else if p.tok.kind == .ellipsis {
|
} else if p.tok.kind == .ellipsis {
|
||||||
p.next()
|
p.next()
|
||||||
|
if is_comptime {
|
||||||
|
p.inside_ct_match_case = true
|
||||||
|
}
|
||||||
p.inside_match_case = true
|
p.inside_match_case = true
|
||||||
expr2 := p.expr(0)
|
expr2 := p.expr(0)
|
||||||
p.inside_match_case = false
|
p.inside_match_case = false
|
||||||
|
p.inside_ct_match_case = false
|
||||||
exprs << ast.RangeExpr{
|
exprs << ast.RangeExpr{
|
||||||
low: expr
|
low: expr
|
||||||
high: expr2
|
high: expr2
|
||||||
|
@ -394,11 +457,24 @@ fn (mut p Parser) match_expr(is_comptime bool) ast.MatchExpr {
|
||||||
}
|
}
|
||||||
branch_last_pos := p.prev_tok.pos()
|
branch_last_pos := p.prev_tok.pos()
|
||||||
// p.warn('match block')
|
// p.warn('match block')
|
||||||
|
if is_comptime {
|
||||||
|
p.inside_ct_match_body = true
|
||||||
|
}
|
||||||
p.inside_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
|
branch_scope := p.scope
|
||||||
p.close_scope()
|
p.close_scope()
|
||||||
p.inside_match_body = false
|
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)
|
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)
|
branch_pos := branch_first_pos.extend_with_last_line(p.tok.pos(), p.tok.line_nr)
|
||||||
post_comments := p.eat_comments()
|
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 {
|
.eq, .ne, .gt, .lt, .ge, .le {
|
||||||
match mut cond.left {
|
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 {
|
ast.Ident {
|
||||||
// $if version == 2
|
// $if version == 2
|
||||||
match mut cond.right {
|
match mut cond.right {
|
||||||
|
|
|
@ -53,6 +53,9 @@ mut:
|
||||||
inside_select bool // to allow `ch <- Struct{} {` inside `select`
|
inside_select bool // to allow `ch <- Struct{} {` inside `select`
|
||||||
inside_match_case bool // to separate `match_expr { }` from `Struct{}`
|
inside_match_case bool // to separate `match_expr { }` from `Struct{}`
|
||||||
inside_match_body bool // to fix eval not used TODO
|
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_unsafe bool
|
||||||
inside_sum_type bool // to prevent parsing inline sum type again
|
inside_sum_type bool // to prevent parsing inline sum type again
|
||||||
inside_asm_template bool
|
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 {
|
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.
|
// 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
|
return p.cur_fn_name.len == 0
|
||||||
&& p.tok.kind != .name
|
&& (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 {
|
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_markused := false
|
||||||
mut is_exported := false
|
mut is_exported := false
|
||||||
|
mut is_weak := false
|
||||||
|
mut is_hidden := false
|
||||||
for ga in attrs {
|
for ga in attrs {
|
||||||
match ga.name {
|
match ga.name {
|
||||||
'export' { is_exported = true }
|
'export' { is_exported = true }
|
||||||
'markused' { is_markused = true }
|
'markused' { is_markused = true }
|
||||||
|
'weak' { is_weak = true }
|
||||||
|
'hidden' { is_hidden = true }
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2687,6 +2695,8 @@ fn (mut p Parser) global_decl() ast.GlobalDecl {
|
||||||
is_markused: is_markused
|
is_markused: is_markused
|
||||||
is_volatile: is_volatile
|
is_volatile: is_volatile
|
||||||
is_exported: is_exported
|
is_exported: is_exported
|
||||||
|
is_weak: is_weak
|
||||||
|
is_hidden: is_hidden
|
||||||
}
|
}
|
||||||
fields << field
|
fields << field
|
||||||
if name !in ast.global_reserved_type_names {
|
if name !in ast.global_reserved_type_names {
|
||||||
|
|
|
@ -480,6 +480,7 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl {
|
||||||
language: language
|
language: language
|
||||||
is_union: is_union
|
is_union: is_union
|
||||||
is_option: is_option
|
is_option: is_option
|
||||||
|
is_aligned: attrs.contains('aligned')
|
||||||
attrs: if is_anon { []ast.Attr{} } else { attrs } // anon structs can't have attributes
|
attrs: if is_anon { []ast.Attr{} } else { attrs } // anon structs can't have attributes
|
||||||
pre_comments: pre_comments
|
pre_comments: pre_comments
|
||||||
end_comments: end_comments
|
end_comments: end_comments
|
||||||
|
|
34
vlib/v/tests/comptime/comptime_if_at_expr_test.v
Normal file
34
vlib/v/tests/comptime/comptime_if_at_expr_test.v
Normal file
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
44
vlib/v/tests/comptime/comptime_match_at_expr_test.v
Normal file
44
vlib/v/tests/comptime/comptime_match_at_expr_test.v
Normal file
|
@ -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'
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue