mirror of
https://github.com/vlang/v.git
synced 2025-09-13 22:42:26 +03:00
This commit is contained in:
parent
7dd91ecef7
commit
a3f86eed1b
12 changed files with 605 additions and 461 deletions
|
@ -1538,7 +1538,6 @@ fn (t Tree) if_branch(node ast.IfBranch) &Node {
|
||||||
obj.add_terse('cond', t.expr(node.cond))
|
obj.add_terse('cond', t.expr(node.cond))
|
||||||
obj.add('pos', t.pos(node.pos))
|
obj.add('pos', t.pos(node.pos))
|
||||||
obj.add('body_pos', t.pos(node.body_pos))
|
obj.add('body_pos', t.pos(node.body_pos))
|
||||||
obj.add_terse('pkg_exist', t.bool_node(node.pkg_exist))
|
|
||||||
obj.add_terse('stmts', t.array_node_stmt(node.stmts))
|
obj.add_terse('stmts', t.array_node_stmt(node.stmts))
|
||||||
obj.add('scope', t.number_node(int(node.scope)))
|
obj.add('scope', t.number_node(int(node.scope)))
|
||||||
obj.add('comments', t.array_node_comment(node.comments))
|
obj.add('comments', t.array_node_comment(node.comments))
|
||||||
|
|
|
@ -1235,7 +1235,6 @@ pub:
|
||||||
comments []Comment
|
comments []Comment
|
||||||
pub mut:
|
pub mut:
|
||||||
cond Expr
|
cond Expr
|
||||||
pkg_exist bool
|
|
||||||
stmts []Stmt
|
stmts []Stmt
|
||||||
scope &Scope = unsafe { nil }
|
scope &Scope = unsafe { nil }
|
||||||
}
|
}
|
||||||
|
@ -2131,6 +2130,8 @@ pub fn (cc ComptimeCall) expr_str() string {
|
||||||
if arg.expr.is_pure_literal() {
|
if arg.expr.is_pure_literal() {
|
||||||
str = "\$${cc.method_name}('${cc.args_var}', ${arg})"
|
str = "\$${cc.method_name}('${cc.args_var}', ${arg})"
|
||||||
}
|
}
|
||||||
|
} else if cc.kind == .pkgconfig {
|
||||||
|
str = "\$${cc.method_name}('${cc.args_var}')"
|
||||||
}
|
}
|
||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,6 +94,13 @@ pub mut:
|
||||||
anon_struct_counter int
|
anon_struct_counter int
|
||||||
anon_union_names map[string]int // anon union name -> union sym idx
|
anon_union_names map[string]int // anon union name -> union sym idx
|
||||||
anon_union_counter int
|
anon_union_counter int
|
||||||
|
comptime_is_true map[string]ComptTimeCondResult // The evaluate cond results for different generic types combination, such as `comptime_is_true['T=int,X=string|main.v|pos ...'] = {true, '!DEFINED(WINDOWS)'}`
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ComptTimeCondResult {
|
||||||
|
pub mut:
|
||||||
|
val bool
|
||||||
|
c_str string
|
||||||
}
|
}
|
||||||
|
|
||||||
// used by vls to avoid leaks
|
// used by vls to avoid leaks
|
||||||
|
|
|
@ -256,7 +256,11 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) {
|
||||||
node.typ = c.expr(mut node.expr)
|
node.typ = c.expr(mut node.expr)
|
||||||
c.unwrap_generic(node.typ)
|
c.unwrap_generic(node.typ)
|
||||||
}
|
}
|
||||||
sym := c.table.final_sym(typ)
|
sym := if node.typ != c.field_data_type {
|
||||||
|
c.table.final_sym(typ)
|
||||||
|
} else {
|
||||||
|
c.table.final_sym(c.comptime.comptime_for_field_type)
|
||||||
|
}
|
||||||
if sym.kind == .placeholder || typ.has_flag(.generic) {
|
if sym.kind == .placeholder || typ.has_flag(.generic) {
|
||||||
c.error('\$for expects a type name or variable name to be used here, but ${sym.name} is not a type or variable name',
|
c.error('\$for expects a type name or variable name to be used here, but ${sym.name} is not a type or variable name',
|
||||||
node.typ_pos)
|
node.typ_pos)
|
||||||
|
@ -655,7 +659,8 @@ fn (mut c Checker) eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.Comp
|
||||||
for i in 0 .. expr.branches.len {
|
for i in 0 .. expr.branches.len {
|
||||||
mut branch := expr.branches[i]
|
mut branch := expr.branches[i]
|
||||||
if !expr.has_else || i < expr.branches.len - 1 {
|
if !expr.has_else || i < expr.branches.len - 1 {
|
||||||
is_true, _ := c.comptime_if_cond(mut branch.cond)
|
mut sb := strings.new_builder(256)
|
||||||
|
is_true, _ := c.comptime_if_cond(mut branch.cond, mut sb)
|
||||||
if is_true {
|
if is_true {
|
||||||
last_stmt := branch.stmts.last()
|
last_stmt := branch.stmts.last()
|
||||||
if last_stmt is ast.ExprStmt {
|
if last_stmt is ast.ExprStmt {
|
||||||
|
@ -771,13 +776,199 @@ fn (mut c Checker) evaluate_once_comptime_if_attribute(mut node ast.Attr) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.inside_ct_attr = true
|
c.inside_ct_attr = true
|
||||||
is_true, _ := c.comptime_if_cond(mut node.ct_expr)
|
mut sb := strings.new_builder(256)
|
||||||
|
is_true, _ := c.comptime_if_cond(mut node.ct_expr, mut sb)
|
||||||
node.ct_skip = !is_true
|
node.ct_skip = !is_true
|
||||||
c.inside_ct_attr = false
|
c.inside_ct_attr = false
|
||||||
node.ct_evaled = true
|
node.ct_evaled = true
|
||||||
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}"')
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut c Checker) get_expr_type(cond ast.Expr) ast.Type {
|
fn (mut c Checker) get_expr_type(cond ast.Expr) ast.Type {
|
||||||
match cond {
|
match cond {
|
||||||
ast.Ident {
|
ast.Ident {
|
||||||
|
@ -854,7 +1045,7 @@ fn (mut c Checker) get_expr_type(cond ast.Expr) ast.Type {
|
||||||
// comptime_if_cond evaluate the `cond` and return (`is_true`, `keep_stmts`)
|
// comptime_if_cond evaluate the `cond` and return (`is_true`, `keep_stmts`)
|
||||||
// `is_true` is the evaluate result of `cond`;
|
// `is_true` is the evaluate result of `cond`;
|
||||||
// `keep_stmts` meaning the branch is a `multi pass branch`, we should keep the branch stmts even `is_true` is false, such as `$if T is int {`
|
// `keep_stmts` meaning the branch is a `multi pass branch`, we should keep the branch stmts even `is_true` is false, such as `$if T is int {`
|
||||||
fn (mut c Checker) comptime_if_cond(mut cond ast.Expr) (bool, bool) {
|
fn (mut c Checker) comptime_if_cond(mut cond ast.Expr, mut sb strings.Builder) (bool, bool) {
|
||||||
mut should_record_ident := false
|
mut should_record_ident := false
|
||||||
mut is_user_ident := false
|
mut is_user_ident := false
|
||||||
mut ident_name := ''
|
mut ident_name := ''
|
||||||
|
@ -873,17 +1064,25 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr) (bool, bool) {
|
||||||
match mut cond {
|
match mut cond {
|
||||||
ast.BoolLiteral {
|
ast.BoolLiteral {
|
||||||
c.expr(mut cond)
|
c.expr(mut cond)
|
||||||
return cond.val, false
|
is_true = cond.val
|
||||||
|
sb.write_string('${is_true}')
|
||||||
|
return is_true, false
|
||||||
}
|
}
|
||||||
ast.ParExpr {
|
ast.ParExpr {
|
||||||
return c.comptime_if_cond(mut cond.expr)
|
sb.write_string('(')
|
||||||
|
is_true_result, multi_pass_stmts := c.comptime_if_cond(mut cond.expr, mut
|
||||||
|
sb)
|
||||||
|
sb.write_string(')')
|
||||||
|
return is_true_result, multi_pass_stmts
|
||||||
}
|
}
|
||||||
ast.PrefixExpr {
|
ast.PrefixExpr {
|
||||||
if cond.op != .not {
|
if cond.op != .not {
|
||||||
c.error('invalid \$if prefix operator, only allow `!`.', cond.pos)
|
c.error('invalid \$if prefix operator, only allow `!`.', cond.pos)
|
||||||
return false, false
|
return false, false
|
||||||
}
|
}
|
||||||
is_true_result, multi_pass_stmts := c.comptime_if_cond(mut cond.right)
|
sb.write_string(cond.op.str())
|
||||||
|
is_true_result, multi_pass_stmts := c.comptime_if_cond(mut cond.right, mut
|
||||||
|
sb)
|
||||||
return !is_true_result, multi_pass_stmts
|
return !is_true_result, multi_pass_stmts
|
||||||
}
|
}
|
||||||
ast.PostfixExpr {
|
ast.PostfixExpr {
|
||||||
|
@ -900,16 +1099,20 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr) (bool, bool) {
|
||||||
should_record_ident = true
|
should_record_ident = true
|
||||||
is_user_ident = true
|
is_user_ident = true
|
||||||
ident_name = cname
|
ident_name = cname
|
||||||
if cname in c.pref.compile_defines {
|
// ifdef := c.comptime_if_to_ifdef(cname, true) or {
|
||||||
return true, false
|
// c.error(err.msg(), cond.pos)
|
||||||
}
|
// return false, false
|
||||||
return false, false
|
//}
|
||||||
|
sb.write_string('defined(CUSTOM_DEFINE_${cname})')
|
||||||
|
is_true = cname in c.pref.compile_defines
|
||||||
|
return is_true, false
|
||||||
}
|
}
|
||||||
ast.InfixExpr {
|
ast.InfixExpr {
|
||||||
match cond.op {
|
match cond.op {
|
||||||
.and, .logical_or {
|
.and, .logical_or {
|
||||||
l, d1 := c.comptime_if_cond(mut cond.left)
|
l, d1 := c.comptime_if_cond(mut cond.left, mut sb)
|
||||||
r, d2 := c.comptime_if_cond(mut cond.right)
|
sb.write_string(' ${cond.op} ')
|
||||||
|
r, d2 := c.comptime_if_cond(mut cond.right, mut sb)
|
||||||
// if at least one of the cond has `keep_stmts`, we should keep stmts
|
// if at least one of the cond has `keep_stmts`, we should keep stmts
|
||||||
return if cond.op == .and { l && r } else { l || r }, d1 || d2
|
return if cond.op == .and { l && r } else { l || r }, d1 || d2
|
||||||
}
|
}
|
||||||
|
@ -979,11 +1182,9 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr) (bool, bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return if cond.op in [.key_in, .key_is] {
|
is_true = if cond.op in [.key_in, .key_is] { is_true } else { !is_true }
|
||||||
is_true, true
|
sb.write_string('${is_true}')
|
||||||
} else {
|
return is_true, true
|
||||||
!is_true, true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if cond.left !in [ast.TypeNode, ast.Ident, ast.SelectorExpr] {
|
if cond.left !in [ast.TypeNode, ast.Ident, ast.SelectorExpr] {
|
||||||
|
@ -1078,6 +1279,7 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr) (bool, bool) {
|
||||||
return false, false
|
return false, false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sb.write_string('${is_true}')
|
||||||
return is_true, false
|
return is_true, false
|
||||||
}
|
}
|
||||||
ast.SelectorExpr {
|
ast.SelectorExpr {
|
||||||
|
@ -1106,9 +1308,11 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr) (bool, bool) {
|
||||||
}
|
}
|
||||||
match cond.op {
|
match cond.op {
|
||||||
.eq {
|
.eq {
|
||||||
|
sb.write_string('${is_true}')
|
||||||
return is_true, true
|
return is_true, true
|
||||||
}
|
}
|
||||||
.ne {
|
.ne {
|
||||||
|
sb.write_string('${!is_true}')
|
||||||
return !is_true, true
|
return !is_true, true
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1153,6 +1357,7 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr) (bool, bool) {
|
||||||
return false, false
|
return false, false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sb.write_string('${is_true}')
|
||||||
return is_true, true
|
return is_true, true
|
||||||
} else if cond.left.field_name == 'return_type' {
|
} else if cond.left.field_name == 'return_type' {
|
||||||
// method.return_type
|
// method.return_type
|
||||||
|
@ -1182,6 +1387,7 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr) (bool, bool) {
|
||||||
return false, false
|
return false, false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sb.write_string('${is_true}')
|
||||||
return is_true, false
|
return is_true, false
|
||||||
} else {
|
} else {
|
||||||
c.error('only support .return_type compare for \$for method',
|
c.error('only support .return_type compare for \$for method',
|
||||||
|
@ -1196,8 +1402,10 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr) (bool, bool) {
|
||||||
}
|
}
|
||||||
ast.BoolLiteral {
|
ast.BoolLiteral {
|
||||||
// field.is_pub == true
|
// field.is_pub == true
|
||||||
l, _ := c.comptime_if_cond(mut cond.left)
|
l, _ := c.comptime_if_cond(mut cond.left, mut sb)
|
||||||
|
sb.write_string(' ${cond.op} ')
|
||||||
r := (cond.right as ast.BoolLiteral).val
|
r := (cond.right as ast.BoolLiteral).val
|
||||||
|
sb.write_string('${r}')
|
||||||
is_true = if cond.op == .eq { l == r } else { l != r }
|
is_true = if cond.op == .eq { l == r } else { l != r }
|
||||||
return is_true, true
|
return is_true, true
|
||||||
}
|
}
|
||||||
|
@ -1239,6 +1447,7 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr) (bool, bool) {
|
||||||
return false, false
|
return false, false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sb.write_string('${is_true}')
|
||||||
return is_true, true
|
return is_true, true
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1269,17 +1478,13 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr) (bool, bool) {
|
||||||
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_if_os {
|
||||||
if !c.pref.output_cross_c {
|
|
||||||
if cname_enum_val := pref.os_from_string(cname) {
|
if cname_enum_val := pref.os_from_string(cname) {
|
||||||
if cname_enum_val == c.pref.os {
|
if cname_enum_val == c.pref.os {
|
||||||
is_true = true
|
is_true = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return is_true, false
|
|
||||||
} else if cname in ast.valid_comptime_if_compilers {
|
} else if cname in ast.valid_comptime_if_compilers {
|
||||||
is_true = pref.cc_from_string(cname) == c.pref.ccompiler_type
|
is_true = pref.cc_from_string(cname) == c.pref.ccompiler_type
|
||||||
return is_true, false
|
|
||||||
} else if cname in ast.valid_comptime_if_platforms {
|
} else if cname in ast.valid_comptime_if_platforms {
|
||||||
if cname == 'aarch64' {
|
if cname == 'aarch64' {
|
||||||
c.note('use `arm64` instead of `aarch64`', cond.pos)
|
c.note('use `arm64` instead of `aarch64`', cond.pos)
|
||||||
|
@ -1321,7 +1526,6 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr) (bool, bool) {
|
||||||
return false, false
|
return false, false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return is_true, false
|
|
||||||
} else if cname in ast.valid_comptime_if_cpu_features {
|
} else if cname in ast.valid_comptime_if_cpu_features {
|
||||||
match cname {
|
match cname {
|
||||||
'x64' {
|
'x64' {
|
||||||
|
@ -1342,7 +1546,6 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr) (bool, bool) {
|
||||||
return false, false
|
return false, false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return is_true, false
|
|
||||||
} else if cname in ast.valid_comptime_if_other {
|
} else if cname in ast.valid_comptime_if_other {
|
||||||
match cname {
|
match cname {
|
||||||
'apk' {
|
'apk' {
|
||||||
|
@ -1414,7 +1617,6 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr) (bool, bool) {
|
||||||
return false, false
|
return false, false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return is_true, false
|
|
||||||
} else if cname !in c.pref.compile_defines_all {
|
} else if cname !in c.pref.compile_defines_all {
|
||||||
if cname == 'linux_or_macos' {
|
if cname == 'linux_or_macos' {
|
||||||
c.error('linux_or_macos is deprecated, use `\$if linux || macos {` instead',
|
c.error('linux_or_macos is deprecated, use `\$if linux || macos {` instead',
|
||||||
|
@ -1441,21 +1643,34 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr) (bool, bool) {
|
||||||
return false, false
|
return false, false
|
||||||
}
|
}
|
||||||
is_true = (expr as ast.BoolLiteral).val
|
is_true = (expr as ast.BoolLiteral).val
|
||||||
return is_true, false
|
|
||||||
} else if cname in c.pref.compile_defines {
|
} else if cname in c.pref.compile_defines {
|
||||||
return true, false
|
is_true = true
|
||||||
}
|
} else {
|
||||||
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) {
|
||||||
|
sb.write_string('defined(${ifdef})')
|
||||||
|
} else {
|
||||||
|
sb.write_string('${is_true}')
|
||||||
|
}
|
||||||
|
return is_true, false
|
||||||
|
}
|
||||||
ast.ComptimeCall {
|
ast.ComptimeCall {
|
||||||
if cond.kind == .pkgconfig {
|
if cond.kind == .pkgconfig {
|
||||||
mut m := pkgconfig.main([cond.args_var]) or {
|
if mut m := pkgconfig.main([cond.args_var]) {
|
||||||
c.error(err.msg(), cond.pos)
|
if _ := m.run() {
|
||||||
return false, true
|
is_true = true
|
||||||
|
} else {
|
||||||
|
// pkgconfig not found, do not issue error, just set false
|
||||||
|
is_true = false
|
||||||
}
|
}
|
||||||
m.run() or { return false, true }
|
} else {
|
||||||
return true, true
|
c.error(err.msg(), cond.pos)
|
||||||
|
is_true = false
|
||||||
|
}
|
||||||
|
sb.write_string('${is_true}')
|
||||||
|
return is_true, true
|
||||||
}
|
}
|
||||||
if cond.kind == .d {
|
if cond.kind == .d {
|
||||||
t := c.expr(mut cond)
|
t := c.expr(mut cond)
|
||||||
|
@ -1464,7 +1679,9 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr) (bool, bool) {
|
||||||
cond.pos)
|
cond.pos)
|
||||||
return false, false
|
return false, false
|
||||||
}
|
}
|
||||||
return cond.compile_value.bool(), false
|
is_true = cond.compile_value.bool()
|
||||||
|
sb.write_string('${is_true}')
|
||||||
|
return is_true, false
|
||||||
}
|
}
|
||||||
c.error('invalid \$if condition: unknown ComptimeCall', cond.pos)
|
c.error('invalid \$if condition: unknown ComptimeCall', cond.pos)
|
||||||
return false, false
|
return false, false
|
||||||
|
@ -1473,6 +1690,7 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr) (bool, bool) {
|
||||||
if c.comptime.comptime_for_field_var != '' && cond.expr is ast.Ident {
|
if c.comptime.comptime_for_field_var != '' && cond.expr is ast.Ident {
|
||||||
if (cond.expr as ast.Ident).name == c.comptime.comptime_for_field_var && cond.field_name in ['is_mut', 'is_pub', 'is_shared', 'is_atomic', 'is_option', 'is_array', 'is_map', 'is_chan', 'is_struct', 'is_alias', 'is_enum'] {
|
if (cond.expr as ast.Ident).name == c.comptime.comptime_for_field_var && cond.field_name in ['is_mut', 'is_pub', 'is_shared', 'is_atomic', 'is_option', 'is_array', 'is_map', 'is_chan', 'is_struct', 'is_alias', 'is_enum'] {
|
||||||
is_true = c.type_resolver.get_comptime_selector_bool_field(cond.field_name)
|
is_true = c.type_resolver.get_comptime_selector_bool_field(cond.field_name)
|
||||||
|
sb.write_string('${is_true}')
|
||||||
return is_true, true
|
return is_true, true
|
||||||
}
|
}
|
||||||
c.error('unknown field `${cond.field_name}` from ${c.comptime.comptime_for_field_var}',
|
c.error('unknown field `${cond.field_name}` from ${c.comptime.comptime_for_field_var}',
|
||||||
|
@ -1481,6 +1699,7 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr) (bool, bool) {
|
||||||
if c.comptime.comptime_for_attr_var != '' && cond.expr is ast.Ident {
|
if c.comptime.comptime_for_attr_var != '' && cond.expr is ast.Ident {
|
||||||
if (cond.expr as ast.Ident).name == c.comptime.comptime_for_attr_var && cond.field_name == 'has_arg' {
|
if (cond.expr as ast.Ident).name == c.comptime.comptime_for_attr_var && cond.field_name == 'has_arg' {
|
||||||
is_true = c.comptime.comptime_for_attr_value.has_arg
|
is_true = c.comptime.comptime_for_attr_value.has_arg
|
||||||
|
sb.write_string('${is_true}')
|
||||||
return is_true, true
|
return is_true, true
|
||||||
}
|
}
|
||||||
c.error('unknown field `${cond.field_name}` from ${c.comptime.comptime_for_attr_var}',
|
c.error('unknown field `${cond.field_name}` from ${c.comptime.comptime_for_attr_var}',
|
||||||
|
@ -1510,6 +1729,7 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr) (bool, bool) {
|
||||||
'is_expand_simple_interpolation' { method.is_expand_simple_interpolation }
|
'is_expand_simple_interpolation' { method.is_expand_simple_interpolation }
|
||||||
else { false }
|
else { false }
|
||||||
}
|
}
|
||||||
|
sb.write_string('${is_true}')
|
||||||
return is_true, true
|
return is_true, true
|
||||||
}
|
}
|
||||||
c.error('unknown field `${cond.field_name}` from ${c.comptime.comptime_for_method_var}',
|
c.error('unknown field `${cond.field_name}` from ${c.comptime.comptime_for_method_var}',
|
||||||
|
|
|
@ -4,6 +4,61 @@ module checker
|
||||||
|
|
||||||
import v.ast
|
import v.ast
|
||||||
import v.token
|
import v.token
|
||||||
|
import v.util
|
||||||
|
import strings
|
||||||
|
|
||||||
|
// gen_branch_context_string generate current branches context string.
|
||||||
|
// context include generic types, `$for`.
|
||||||
|
fn (mut c Checker) gen_branch_context_string() string {
|
||||||
|
mut arr := []string{}
|
||||||
|
|
||||||
|
// gen `T=int,X=string`
|
||||||
|
if c.table.cur_fn.generic_names.len > 0
|
||||||
|
&& c.table.cur_fn.generic_names.len == c.table.cur_concrete_types.len {
|
||||||
|
for i in 0 .. c.table.cur_fn.generic_names.len {
|
||||||
|
arr << c.table.cur_fn.generic_names[i] + '=' +
|
||||||
|
util.strip_main_name(c.table.type_to_str(c.table.cur_concrete_types[i]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// gen comptime `$for`
|
||||||
|
if c.comptime.inside_comptime_for {
|
||||||
|
// variants
|
||||||
|
if c.comptime.comptime_for_variant_var.len > 0 {
|
||||||
|
variant := c.table.type_to_str(c.type_resolver.get_ct_type_or_default('${c.comptime.comptime_for_variant_var}.typ',
|
||||||
|
ast.no_type))
|
||||||
|
arr << c.comptime.comptime_for_variant_var + '.typ=' + variant
|
||||||
|
}
|
||||||
|
// fields
|
||||||
|
if c.comptime.comptime_for_field_var.len > 0 {
|
||||||
|
arr << c.comptime.comptime_for_field_var + '.name=' +
|
||||||
|
c.comptime.comptime_for_field_value.name
|
||||||
|
}
|
||||||
|
// values
|
||||||
|
if c.comptime.comptime_for_enum_var.len > 0 {
|
||||||
|
enum_var := c.table.type_to_str(c.type_resolver.get_ct_type_or_default('${c.comptime.comptime_for_enum_var}.typ',
|
||||||
|
ast.void_type))
|
||||||
|
arr << c.comptime.comptime_for_enum_var + '.typ=' + enum_var
|
||||||
|
}
|
||||||
|
// attributes
|
||||||
|
if c.comptime.comptime_for_attr_var.len > 0 {
|
||||||
|
arr << c.comptime.comptime_for_attr_var + '.name=' +
|
||||||
|
c.comptime.comptime_for_attr_value.name
|
||||||
|
}
|
||||||
|
// methods
|
||||||
|
if c.comptime.comptime_for_method_var.len > 0 {
|
||||||
|
arr << c.comptime.comptime_for_method_var + '.name=' +
|
||||||
|
c.comptime.comptime_for_method.name
|
||||||
|
}
|
||||||
|
// args
|
||||||
|
if c.comptime.comptime_for_method_param_var.len > 0 {
|
||||||
|
arg_var := c.table.type_to_str(c.type_resolver.get_ct_type_or_default('${c.comptime.comptime_for_method_param_var}.typ',
|
||||||
|
ast.void_type))
|
||||||
|
arr << c.comptime.comptime_for_method_param_var + '.typ=' + arg_var
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr.join(',')
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
|
fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
|
||||||
if_kind := if node.is_comptime { '\$if' } else { 'if' }
|
if_kind := if node.is_comptime { '\$if' } else { 'if' }
|
||||||
|
@ -40,8 +95,10 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
|
||||||
c.comptime.inside_comptime_if = last_in_comptime_if
|
c.comptime.inside_comptime_if = last_in_comptime_if
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in 0 .. node.branches.len {
|
comptime_branch_context_str := if node.is_comptime { c.gen_branch_context_string() } else { '' }
|
||||||
mut branch := node.branches[i]
|
|
||||||
|
for i, mut branch in node.branches {
|
||||||
|
mut comptime_remove_curr_branch_stmts := false
|
||||||
if branch.cond is ast.ParExpr && !c.pref.translated && !c.file.is_translated {
|
if branch.cond is ast.ParExpr && !c.pref.translated && !c.file.is_translated {
|
||||||
c.warn('unnecessary `()` in `${if_kind}` condition, use `${if_kind} expr {` instead of `${if_kind} (expr) {`.',
|
c.warn('unnecessary `()` in `${if_kind}` condition, use `${if_kind} expr {` instead of `${if_kind} (expr) {`.',
|
||||||
branch.pos)
|
branch.pos)
|
||||||
|
@ -49,17 +106,42 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
|
||||||
if !node.has_else || i < node.branches.len - 1 {
|
if !node.has_else || i < node.branches.len - 1 {
|
||||||
// if branch
|
// if branch
|
||||||
if node.is_comptime {
|
if node.is_comptime {
|
||||||
|
// `idx_str` is composed of two parts:
|
||||||
|
// The first part represents the current context of the branch statement, `comptime_branch_context_str`, formatted like `T=int,X=string,method.name=json`
|
||||||
|
// The second part indicates the branch's location in the source file.
|
||||||
|
// This format must match what is in `cgen`.
|
||||||
|
idx_str := comptime_branch_context_str + '|${c.file.path}|${branch.cond.pos()}|'
|
||||||
c.comptime.inside_comptime_if = true
|
c.comptime.inside_comptime_if = true
|
||||||
comptime_if_result, comptime_if_multi_pass_branch = c.comptime_if_cond(mut branch.cond)
|
mut sb := strings.new_builder(256)
|
||||||
node.branches[i].pkg_exist = comptime_if_result
|
comptime_if_result, comptime_if_multi_pass_branch = c.comptime_if_cond(mut branch.cond, mut
|
||||||
|
sb)
|
||||||
if comptime_if_multi_pass_branch {
|
if comptime_if_multi_pass_branch {
|
||||||
comptime_if_has_multi_pass_branch = true
|
comptime_if_has_multi_pass_branch = true
|
||||||
}
|
}
|
||||||
if !comptime_if_has_multi_pass_branch && comptime_if_found_branch {
|
|
||||||
// when all prev branchs are single pass branchs, and already has a true branch:
|
if comptime_if_found_branch {
|
||||||
// remove following branchs' stmts by overwrite `comptime_if_result`
|
|
||||||
comptime_if_result = false
|
comptime_if_result = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !comptime_if_has_multi_pass_branch
|
||||||
|
&& (comptime_if_found_branch || !comptime_if_result) {
|
||||||
|
// when all prev branchs are single pass branchs,
|
||||||
|
// 1. already has a true branch or
|
||||||
|
// 2. `comptime_if_result is` false
|
||||||
|
// remove current branchs' stmts
|
||||||
|
comptime_remove_curr_branch_stmts = true
|
||||||
|
}
|
||||||
|
if old_val := c.table.comptime_is_true[idx_str] {
|
||||||
|
if old_val.val != comptime_if_result {
|
||||||
|
c.error('checker erro1r : branch eval wrong', branch.cond.pos())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set `comptime_is_true` which can be used by `cgen`
|
||||||
|
c.table.comptime_is_true[idx_str] = ast.ComptTimeCondResult{
|
||||||
|
val: comptime_if_result
|
||||||
|
c_str: sb.str()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// check condition type is boolean
|
// check condition type is boolean
|
||||||
c.expected_type = ast.bool_type
|
c.expected_type = ast.bool_type
|
||||||
|
@ -78,6 +160,17 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
|
||||||
comptime_if_result = !comptime_if_found_branch
|
comptime_if_result = !comptime_if_found_branch
|
||||||
// if all other branchs has at least one multi pass branch, we should keep this else branch
|
// if all other branchs has at least one multi pass branch, we should keep this else branch
|
||||||
comptime_if_multi_pass_branch = comptime_if_has_multi_pass_branch
|
comptime_if_multi_pass_branch = comptime_if_has_multi_pass_branch
|
||||||
|
if !comptime_if_has_multi_pass_branch && comptime_if_found_branch {
|
||||||
|
// when all prev branchs are single pass branchs, already has a true branch
|
||||||
|
// remove current branchs' stmts
|
||||||
|
comptime_remove_curr_branch_stmts = true
|
||||||
|
}
|
||||||
|
// hack: as a `else` has no `cond`, so we use `branch.pos` here
|
||||||
|
idx_str := comptime_branch_context_str + '|${c.file.path}|${branch.pos}|'
|
||||||
|
c.table.comptime_is_true[idx_str] = ast.ComptTimeCondResult{
|
||||||
|
val: comptime_if_result
|
||||||
|
c_str: ''
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if mut branch.cond is ast.IfGuardExpr {
|
if mut branch.cond is ast.IfGuardExpr {
|
||||||
|
@ -119,10 +212,18 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
|
||||||
if c.fn_level == 0 && c.pref.output_cross_c {
|
if c.fn_level == 0 && c.pref.output_cross_c {
|
||||||
// do not skip any of the branches for top level `$if OS {`
|
// do not skip any of the branches for top level `$if OS {`
|
||||||
// statements, in `-cross` mode
|
// statements, in `-cross` mode
|
||||||
comptime_if_multi_pass_branch = true
|
comptime_remove_curr_branch_stmts = false
|
||||||
c.skip_flags = false
|
c.skip_flags = false
|
||||||
|
// hack: because `else` branch has no `cond`, so create an Ident, set the `pos`, for `hash_stmt()` work.
|
||||||
|
if branch.cond is ast.NodeError {
|
||||||
|
c.ct_cond_stack << ast.Ident{
|
||||||
|
name: '__else_branch__'
|
||||||
|
pos: branch.pos
|
||||||
|
}
|
||||||
|
} else {
|
||||||
c.ct_cond_stack << branch.cond
|
c.ct_cond_stack << branch.cond
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if !c.skip_flags {
|
if !c.skip_flags {
|
||||||
if node_is_expr {
|
if node_is_expr {
|
||||||
c.stmts_ending_with_expression(mut branch.stmts, c.expected_or_type)
|
c.stmts_ending_with_expression(mut branch.stmts, c.expected_or_type)
|
||||||
|
@ -147,9 +248,6 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
|
||||||
c.stmts(mut branch.stmts)
|
c.stmts(mut branch.stmts)
|
||||||
c.check_non_expr_branch_last_stmt(branch.stmts)
|
c.check_non_expr_branch_last_stmt(branch.stmts)
|
||||||
}
|
}
|
||||||
} else if !comptime_if_multi_pass_branch && !comptime_if_result {
|
|
||||||
// this branch is not a multi pass branch, and current cond result is false, remove branch stmts
|
|
||||||
node.branches[i].stmts = []
|
|
||||||
}
|
}
|
||||||
c.skip_flags = cur_skip_flags
|
c.skip_flags = cur_skip_flags
|
||||||
if c.fn_level == 0 && c.pref.output_cross_c && c.ct_cond_stack.len > 0 {
|
if c.fn_level == 0 && c.pref.output_cross_c && c.ct_cond_stack.len > 0 {
|
||||||
|
@ -322,6 +420,11 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
|
||||||
nbranches_without_return++
|
nbranches_without_return++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if comptime_remove_curr_branch_stmts {
|
||||||
|
// remove the branch statements since they may contain OS-specific code.
|
||||||
|
branch.stmts = []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if nbranches_with_return > 0 {
|
if nbranches_with_return > 0 {
|
||||||
if nbranches_with_return == node.branches.len {
|
if nbranches_with_return == node.branches.len {
|
||||||
|
|
|
@ -1030,16 +1030,16 @@ pub fn (mut g Gen) init() {
|
||||||
if g.pref.gc_mode in [.boehm_full, .boehm_incr, .boehm_full_opt, .boehm_incr_opt, .boehm_leak] {
|
if g.pref.gc_mode in [.boehm_full, .boehm_incr, .boehm_full_opt, .boehm_incr_opt, .boehm_leak] {
|
||||||
g.comptime_definitions.writeln('#define _VGCBOEHM (1)')
|
g.comptime_definitions.writeln('#define _VGCBOEHM (1)')
|
||||||
}
|
}
|
||||||
if g.pref.is_debug || 'debug' in g.pref.compile_defines {
|
if g.pref.is_debug {
|
||||||
g.comptime_definitions.writeln('#define _VDEBUG (1)')
|
g.comptime_definitions.writeln('#define _VDEBUG (1)')
|
||||||
}
|
}
|
||||||
if g.pref.is_prod || 'prod' in g.pref.compile_defines {
|
if g.pref.is_prod {
|
||||||
g.comptime_definitions.writeln('#define _VPROD (1)')
|
g.comptime_definitions.writeln('#define _VPROD (1)')
|
||||||
}
|
}
|
||||||
if g.pref.is_test || 'test' in g.pref.compile_defines {
|
if g.pref.is_test {
|
||||||
g.comptime_definitions.writeln('#define _VTEST (1)')
|
g.comptime_definitions.writeln('#define _VTEST (1)')
|
||||||
}
|
}
|
||||||
if g.pref.is_prof || 'profile' in g.pref.compile_defines {
|
if g.pref.is_prof {
|
||||||
g.comptime_definitions.writeln('#define _VPROFILE (1)')
|
g.comptime_definitions.writeln('#define _VPROFILE (1)')
|
||||||
}
|
}
|
||||||
if g.pref.autofree {
|
if g.pref.autofree {
|
||||||
|
@ -5728,15 +5728,27 @@ fn (mut g Gen) hash_stmt_guarded_include(node ast.HashStmt) string {
|
||||||
fn (mut g Gen) hash_stmt(node ast.HashStmt) {
|
fn (mut g Gen) hash_stmt(node ast.HashStmt) {
|
||||||
line_nr := node.pos.line_nr + 1
|
line_nr := node.pos.line_nr + 1
|
||||||
mut ct_condition := ''
|
mut ct_condition := ''
|
||||||
|
|
||||||
if node.ct_conds.len > 0 {
|
if node.ct_conds.len > 0 {
|
||||||
ct_condition_start := g.out.len
|
mut comptime_branch_context_str := g.gen_branch_context_string()
|
||||||
|
mut is_true := ast.ComptTimeCondResult{}
|
||||||
|
mut sb := strings.new_builder(256)
|
||||||
for idx, ct_expr in node.ct_conds {
|
for idx, ct_expr in node.ct_conds {
|
||||||
g.comptime_if_cond(ct_expr, false)
|
idx_str := comptime_branch_context_str + '|${g.file.path}|${ct_expr.pos()}|'
|
||||||
|
if comptime_is_true := g.table.comptime_is_true[idx_str] {
|
||||||
|
// `g.table.comptime_is_true` are the branch condition results set by `checker`
|
||||||
|
is_true = comptime_is_true
|
||||||
|
} else {
|
||||||
|
g.error('checker error: condition result idx string not found => [${idx_str}]',
|
||||||
|
ct_expr.pos())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sb.write_string(is_true.c_str)
|
||||||
if idx < node.ct_conds.len - 1 {
|
if idx < node.ct_conds.len - 1 {
|
||||||
g.write(' && ')
|
sb.write_string(' && ')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ct_condition = g.out.cut_to(ct_condition_start).trim_space()
|
ct_condition = sb.str()
|
||||||
}
|
}
|
||||||
// #include etc
|
// #include etc
|
||||||
if node.kind == 'include' {
|
if node.kind == 'include' {
|
||||||
|
|
|
@ -5,6 +5,7 @@ module c
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import v.ast
|
import v.ast
|
||||||
|
import v.token
|
||||||
import v.util
|
import v.util
|
||||||
import v.pref
|
import v.pref
|
||||||
import v.type_resolver
|
import v.type_resolver
|
||||||
|
@ -313,6 +314,59 @@ fn (mut g Gen) comptime_at(node ast.AtExpr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// gen_branch_context_string generate current branches context string.
|
||||||
|
// context include generic types, `$for`.
|
||||||
|
fn (mut g Gen) gen_branch_context_string() string {
|
||||||
|
mut arr := []string{}
|
||||||
|
|
||||||
|
// gen `T=int,X=string`
|
||||||
|
if g.cur_fn != unsafe { nil } && g.cur_fn.generic_names.len > 0
|
||||||
|
&& g.cur_fn.generic_names.len == g.cur_concrete_types.len {
|
||||||
|
for i in 0 .. g.cur_fn.generic_names.len {
|
||||||
|
arr << g.cur_fn.generic_names[i] + '=' +
|
||||||
|
util.strip_main_name(g.table.type_to_str(g.cur_concrete_types[i]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// gen comptime `$for`
|
||||||
|
if g.comptime.inside_comptime_for {
|
||||||
|
// variants
|
||||||
|
if g.comptime.comptime_for_variant_var.len > 0 {
|
||||||
|
variant := g.table.type_to_str(g.type_resolver.get_ct_type_or_default('${g.comptime.comptime_for_variant_var}.typ',
|
||||||
|
ast.no_type))
|
||||||
|
arr << g.comptime.comptime_for_variant_var + '.typ=' + variant
|
||||||
|
}
|
||||||
|
// fields
|
||||||
|
if g.comptime.comptime_for_field_var.len > 0 {
|
||||||
|
arr << g.comptime.comptime_for_field_var + '.name=' +
|
||||||
|
g.comptime.comptime_for_field_value.name
|
||||||
|
}
|
||||||
|
// values
|
||||||
|
if g.comptime.comptime_for_enum_var.len > 0 {
|
||||||
|
enum_var := g.table.type_to_str(g.type_resolver.get_ct_type_or_default('${g.comptime.comptime_for_enum_var}.typ',
|
||||||
|
ast.void_type))
|
||||||
|
arr << g.comptime.comptime_for_enum_var + '.typ=' + enum_var
|
||||||
|
}
|
||||||
|
// attributes
|
||||||
|
if g.comptime.comptime_for_attr_var.len > 0 {
|
||||||
|
arr << g.comptime.comptime_for_attr_var + '.name=' +
|
||||||
|
g.comptime.comptime_for_attr_value.name
|
||||||
|
}
|
||||||
|
// methods
|
||||||
|
if g.comptime.comptime_for_method_var.len > 0 {
|
||||||
|
arr << g.comptime.comptime_for_method_var + '.name=' +
|
||||||
|
g.comptime.comptime_for_method.name
|
||||||
|
}
|
||||||
|
// args
|
||||||
|
if g.comptime.comptime_for_method_param_var.len > 0 {
|
||||||
|
arg_var := g.table.type_to_str(g.type_resolver.get_ct_type_or_default('${g.comptime.comptime_for_method_param_var}.typ',
|
||||||
|
ast.void_type))
|
||||||
|
arr << g.comptime.comptime_for_method_param_var + '.typ=' + arg_var
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr.join(',')
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut g Gen) comptime_if(node ast.IfExpr) {
|
fn (mut g Gen) comptime_if(node ast.IfExpr) {
|
||||||
if !node.is_expr && !node.has_else && node.branches.len == 1 {
|
if !node.is_expr && !node.has_else && node.branches.len == 1 {
|
||||||
if node.branches[0].stmts.len == 0 {
|
if node.branches[0].stmts.len == 0 {
|
||||||
|
@ -346,32 +400,42 @@ fn (mut g Gen) comptime_if(node ast.IfExpr) {
|
||||||
} else {
|
} else {
|
||||||
''
|
''
|
||||||
}
|
}
|
||||||
mut comptime_if_stmts_skip := false // don't write any statements if the condition is false
|
|
||||||
// (so that for example windows calls don't get generated inside `$if macos` which
|
|
||||||
// will lead to compilation errors)
|
|
||||||
mut comptime_may_skip_else := false
|
|
||||||
|
|
||||||
|
mut comptime_branch_context_str := g.gen_branch_context_string()
|
||||||
|
mut is_true := ast.ComptTimeCondResult{}
|
||||||
for i, branch in node.branches {
|
for i, branch in node.branches {
|
||||||
start_pos := g.out.len
|
start_pos := g.out.len
|
||||||
if comptime_may_skip_else {
|
// `idx_str` is composed of two parts:
|
||||||
continue // if we already have a known true, ignore other branches
|
// The first part represents the current context of the branch statement, `comptime_branch_context_str`, formatted like `T=int,X=string,method.name=json`
|
||||||
}
|
// The second part indicates the branch's location in the source file.
|
||||||
if i == node.branches.len - 1 && node.has_else {
|
// This format must match what is in `checker`.
|
||||||
g.writeln('#else')
|
idx_str := if branch.cond.pos() == token.Pos{} {
|
||||||
comptime_if_stmts_skip = comptime_may_skip_else
|
comptime_branch_context_str + '|${g.file.path}|${branch.pos}|'
|
||||||
} else {
|
} else {
|
||||||
|
comptime_branch_context_str + '|${g.file.path}|${branch.cond.pos()}|'
|
||||||
|
}
|
||||||
|
if comptime_is_true := g.table.comptime_is_true[idx_str] {
|
||||||
|
// `g.table.comptime_is_true` are the branch condition results set by `checker`
|
||||||
|
is_true = comptime_is_true
|
||||||
|
} else {
|
||||||
|
g.error('checker error: condition result idx string not found => [${idx_str}]',
|
||||||
|
node.branches[i].cond.pos())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !node.has_else || i < node.branches.len - 1 {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
g.write('#if ')
|
g.write('#if ')
|
||||||
} else {
|
} else {
|
||||||
g.write('#elif ')
|
g.write('#elif ')
|
||||||
}
|
}
|
||||||
comptime_if_stmts_skip, comptime_may_skip_else = g.comptime_if_cond(branch.cond,
|
// directly use `checker` evaluate results
|
||||||
branch.pkg_exist)
|
// for `cgen`, we can use `is_true.c_str` or `is_true.value` here
|
||||||
if !comptime_if_stmts_skip && comptime_may_skip_else {
|
g.writeln('${is_true.c_str}')
|
||||||
comptime_may_skip_else = false // if the cond is false, not skip else branch
|
$if debug_comptime_branch_context ? {
|
||||||
|
g.writeln('/* ${node.branches[i].cond} | generic=[${comptime_branch_context_str}] */')
|
||||||
}
|
}
|
||||||
comptime_if_stmts_skip = !comptime_if_stmts_skip
|
} else {
|
||||||
g.writeln('')
|
g.writeln('#else')
|
||||||
}
|
}
|
||||||
expr_str := g.out.last_n(g.out.len - start_pos).trim_space()
|
expr_str := g.out.last_n(g.out.len - start_pos).trim_space()
|
||||||
if expr_str != '' {
|
if expr_str != '' {
|
||||||
|
@ -430,7 +494,7 @@ fn (mut g Gen) comptime_if(node ast.IfExpr) {
|
||||||
if should_create_scope {
|
if should_create_scope {
|
||||||
g.writeln('{')
|
g.writeln('{')
|
||||||
}
|
}
|
||||||
if !comptime_if_stmts_skip {
|
if is_true.val {
|
||||||
g.stmts(branch.stmts)
|
g.stmts(branch.stmts)
|
||||||
}
|
}
|
||||||
if should_create_scope {
|
if should_create_scope {
|
||||||
|
@ -494,349 +558,6 @@ fn (mut g Gen) get_expr_type(cond ast.Expr) ast.Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns the value of the bool comptime expression and if next branches may be discarded
|
|
||||||
// returning `false` means the statements inside the $if can be skipped
|
|
||||||
fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) {
|
|
||||||
match cond {
|
|
||||||
ast.BoolLiteral {
|
|
||||||
g.expr(cond)
|
|
||||||
return cond.val, true
|
|
||||||
}
|
|
||||||
ast.ParExpr {
|
|
||||||
g.write('(')
|
|
||||||
is_cond_true, may_discard := g.comptime_if_cond(cond.expr, pkg_exist)
|
|
||||||
g.write(')')
|
|
||||||
return is_cond_true, may_discard
|
|
||||||
}
|
|
||||||
ast.PrefixExpr {
|
|
||||||
g.write(cond.op.str())
|
|
||||||
is_cond_true, _ := g.comptime_if_cond(cond.right, pkg_exist)
|
|
||||||
if cond.op == .not {
|
|
||||||
if cond.right in [ast.BoolLiteral, ast.SelectorExpr] {
|
|
||||||
return !is_cond_true, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return is_cond_true, false
|
|
||||||
}
|
|
||||||
ast.PostfixExpr {
|
|
||||||
dname := (cond.expr as ast.Ident).name
|
|
||||||
ifdef := g.comptime_if_to_ifdef(dname, true) or {
|
|
||||||
verror(err.str())
|
|
||||||
return false, true
|
|
||||||
}
|
|
||||||
g.write('defined(${ifdef})')
|
|
||||||
if dname in g.pref.compile_defines_all && dname !in g.pref.compile_defines {
|
|
||||||
return false, true
|
|
||||||
} else {
|
|
||||||
return true, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast.InfixExpr {
|
|
||||||
match cond.op {
|
|
||||||
.and, .logical_or {
|
|
||||||
l, d1 := g.comptime_if_cond(cond.left, pkg_exist)
|
|
||||||
g.write(' ${cond.op} ')
|
|
||||||
r, d2 := g.comptime_if_cond(cond.right, pkg_exist)
|
|
||||||
return if cond.op == .and { l && r } else { l || r }, d1 && d1 == d2
|
|
||||||
}
|
|
||||||
.key_is, .not_is {
|
|
||||||
if cond.left in [ast.TypeNode, ast.Ident, ast.SelectorExpr]
|
|
||||||
&& cond.right in [ast.ComptimeType, ast.TypeNode] {
|
|
||||||
exp_type := g.get_expr_type(cond.left)
|
|
||||||
if cond.right is ast.ComptimeType {
|
|
||||||
is_true := g.type_resolver.is_comptime_type(exp_type, cond.right)
|
|
||||||
if cond.op == .key_is {
|
|
||||||
if is_true {
|
|
||||||
g.write('1')
|
|
||||||
} else {
|
|
||||||
g.write('0')
|
|
||||||
}
|
|
||||||
return is_true, true
|
|
||||||
} else {
|
|
||||||
if is_true {
|
|
||||||
g.write('0')
|
|
||||||
} else {
|
|
||||||
g.write('1')
|
|
||||||
}
|
|
||||||
return !is_true, true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
got_type := g.unwrap_generic((cond.right as ast.TypeNode).typ)
|
|
||||||
got_sym := g.table.sym(got_type)
|
|
||||||
|
|
||||||
if got_sym.kind == .interface && got_sym.info is ast.Interface {
|
|
||||||
is_true := exp_type.has_flag(.option) == got_type.has_flag(.option)
|
|
||||||
&& g.table.does_type_implement_interface(exp_type, got_type)
|
|
||||||
if cond.op == .key_is {
|
|
||||||
if is_true {
|
|
||||||
g.write('1 && ${exp_type.has_flag(.option)} == ${got_type.has_flag(.option)}')
|
|
||||||
} else {
|
|
||||||
g.write('0')
|
|
||||||
}
|
|
||||||
return is_true, true
|
|
||||||
} else if cond.op == .not_is {
|
|
||||||
if is_true {
|
|
||||||
g.write('0')
|
|
||||||
} else {
|
|
||||||
g.write('1')
|
|
||||||
}
|
|
||||||
return !is_true, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if got_sym.info is ast.FnType && cond.left is ast.Ident
|
|
||||||
&& g.comptime.comptime_for_method_var == cond.left.name {
|
|
||||||
is_compatible := g.table.fn_signature(got_sym.info.func,
|
|
||||||
skip_receiver: true
|
|
||||||
type_only: true
|
|
||||||
) == g.table.fn_signature(g.comptime.comptime_for_method,
|
|
||||||
skip_receiver: true
|
|
||||||
type_only: true
|
|
||||||
)
|
|
||||||
if cond.op == .key_is {
|
|
||||||
g.write(int(is_compatible).str())
|
|
||||||
return is_compatible, true
|
|
||||||
} else {
|
|
||||||
g.write(int(!is_compatible).str())
|
|
||||||
return !is_compatible, true
|
|
||||||
}
|
|
||||||
} else if cond.op == .key_is {
|
|
||||||
g.write('${int(exp_type.idx())} == ${int(got_type.idx())} && ${exp_type.has_flag(.option)} == ${got_type.has_flag(.option)}')
|
|
||||||
return exp_type == got_type, true
|
|
||||||
} else {
|
|
||||||
g.write('${int(exp_type.idx())} != ${int(got_type.idx())}')
|
|
||||||
return exp_type != got_type, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.eq, .ne {
|
|
||||||
// TODO: Implement `$if method.args.len == 1`
|
|
||||||
if cond.left is ast.SelectorExpr && (g.comptime.comptime_for_field_var.len > 0
|
|
||||||
|| g.comptime.comptime_for_method != unsafe { nil }
|
|
||||||
|| cond.left.name_type != 0) {
|
|
||||||
if cond.right is ast.StringLiteral {
|
|
||||||
if cond.left.expr is ast.Ident && cond.left.field_name == 'name' {
|
|
||||||
if g.comptime.comptime_for_method_var.len > 0
|
|
||||||
&& cond.left.expr.name == g.comptime.comptime_for_method_var {
|
|
||||||
is_true := if cond.op == .eq {
|
|
||||||
g.comptime.comptime_for_method.name == cond.right.val
|
|
||||||
} else {
|
|
||||||
g.comptime.comptime_for_method.name != cond.right.val
|
|
||||||
}
|
|
||||||
if is_true {
|
|
||||||
g.write('1')
|
|
||||||
} else {
|
|
||||||
g.write('0')
|
|
||||||
}
|
|
||||||
return is_true, true
|
|
||||||
} else if g.comptime.comptime_for_field_var.len > 0
|
|
||||||
&& cond.left.expr.name == g.comptime.comptime_for_field_var {
|
|
||||||
is_true := if cond.op == .eq {
|
|
||||||
g.comptime.comptime_for_field_value.name == cond.right.val
|
|
||||||
} else {
|
|
||||||
g.comptime.comptime_for_field_value.name != cond.right.val
|
|
||||||
}
|
|
||||||
if is_true {
|
|
||||||
g.write('1')
|
|
||||||
} else {
|
|
||||||
g.write('0')
|
|
||||||
}
|
|
||||||
return is_true, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if cond.right is ast.IntegerLiteral {
|
|
||||||
if g.comptime.is_comptime_selector_field_name(cond.left, 'indirections') {
|
|
||||||
left_muls := if cond.left.name_type != 0 {
|
|
||||||
g.unwrap_generic(cond.left.name_type).nr_muls()
|
|
||||||
} else {
|
|
||||||
g.comptime.comptime_for_field_type.nr_muls()
|
|
||||||
}
|
|
||||||
is_true := match cond.op {
|
|
||||||
.eq { left_muls == cond.right.val.i64() }
|
|
||||||
.ne { left_muls != cond.right.val.i64() }
|
|
||||||
else { false }
|
|
||||||
}
|
|
||||||
if is_true {
|
|
||||||
g.write('1')
|
|
||||||
} else {
|
|
||||||
g.write('0')
|
|
||||||
}
|
|
||||||
return is_true, true
|
|
||||||
} else if g.comptime.comptime_for_method_var != ''
|
|
||||||
&& cond.left.expr is ast.Ident
|
|
||||||
&& cond.left.expr.name == g.comptime.comptime_for_method_var
|
|
||||||
&& cond.left.field_name == 'return_type' {
|
|
||||||
is_true := match cond.op {
|
|
||||||
.eq { g.comptime.comptime_for_method_ret_type.idx() == cond.right.val.i64() }
|
|
||||||
.ne { g.comptime.comptime_for_method_ret_type.idx() != cond.right.val.i64() }
|
|
||||||
else { false }
|
|
||||||
}
|
|
||||||
if is_true {
|
|
||||||
g.write('1')
|
|
||||||
} else {
|
|
||||||
g.write('0')
|
|
||||||
}
|
|
||||||
return is_true, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if cond.left is ast.SelectorExpr || cond.right is ast.SelectorExpr {
|
|
||||||
l, d1 := g.comptime_if_cond(cond.left, pkg_exist)
|
|
||||||
g.write(' ${cond.op} ')
|
|
||||||
r, d2 := g.comptime_if_cond(cond.right, pkg_exist)
|
|
||||||
return if cond.op == .eq { l == r } else { l != r }, d1 && d1 == d2
|
|
||||||
}
|
|
||||||
if cond.left is ast.SizeOf && cond.left.typ != 0
|
|
||||||
&& cond.right is ast.IntegerLiteral {
|
|
||||||
// TODO: support struct.fieldname
|
|
||||||
s, _ := g.table.type_size(g.unwrap_generic(cond.left.typ))
|
|
||||||
right := cond.right as ast.IntegerLiteral
|
|
||||||
is_true := match cond.op {
|
|
||||||
.eq { s == right.val.i64() }
|
|
||||||
.ne { s != right.val.i64() }
|
|
||||||
else { false }
|
|
||||||
}
|
|
||||||
if is_true {
|
|
||||||
g.write('1')
|
|
||||||
} else {
|
|
||||||
g.write('0')
|
|
||||||
}
|
|
||||||
return is_true, true
|
|
||||||
} else {
|
|
||||||
g.write('1')
|
|
||||||
return true, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.key_in, .not_in {
|
|
||||||
if cond.left in [ast.TypeNode, ast.SelectorExpr, ast.Ident]
|
|
||||||
&& cond.right is ast.ArrayInit {
|
|
||||||
checked_type := g.get_expr_type(cond.left)
|
|
||||||
|
|
||||||
for expr in cond.right.exprs {
|
|
||||||
if expr is ast.ComptimeType {
|
|
||||||
if g.type_resolver.is_comptime_type(checked_type, expr as ast.ComptimeType) {
|
|
||||||
if cond.op == .key_in {
|
|
||||||
g.write('1')
|
|
||||||
} else {
|
|
||||||
g.write('0')
|
|
||||||
}
|
|
||||||
return cond.op == .key_in, true
|
|
||||||
}
|
|
||||||
} else if expr is ast.TypeNode {
|
|
||||||
got_type := g.unwrap_generic(expr.typ)
|
|
||||||
if checked_type.idx() == got_type.idx()
|
|
||||||
&& checked_type.has_flag(.option) == got_type.has_flag(.option) {
|
|
||||||
if cond.op == .key_in {
|
|
||||||
g.write('1')
|
|
||||||
} else {
|
|
||||||
g.write('0')
|
|
||||||
}
|
|
||||||
return cond.op == .key_in, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if cond.op == .not_in {
|
|
||||||
g.write('1')
|
|
||||||
} else {
|
|
||||||
g.write('0')
|
|
||||||
}
|
|
||||||
return cond.op == .not_in, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.gt, .lt, .ge, .le {
|
|
||||||
if cond.left is ast.SelectorExpr && cond.right is ast.IntegerLiteral
|
|
||||||
&& g.comptime.is_comptime_selector_field_name(cond.left, 'indirections') {
|
|
||||||
left := cond.left as ast.SelectorExpr
|
|
||||||
left_muls := if left.name_type != 0 {
|
|
||||||
g.unwrap_generic(left.name_type).nr_muls()
|
|
||||||
} else {
|
|
||||||
g.comptime.comptime_for_field_type.nr_muls()
|
|
||||||
}
|
|
||||||
is_true := match cond.op {
|
|
||||||
.gt { left_muls > cond.right.val.i64() }
|
|
||||||
.lt { left_muls < cond.right.val.i64() }
|
|
||||||
.ge { left_muls >= cond.right.val.i64() }
|
|
||||||
.le { left_muls <= cond.right.val.i64() }
|
|
||||||
else { false }
|
|
||||||
}
|
|
||||||
if is_true {
|
|
||||||
g.write('1')
|
|
||||||
} else {
|
|
||||||
g.write('0')
|
|
||||||
}
|
|
||||||
return is_true, true
|
|
||||||
}
|
|
||||||
if cond.left is ast.SizeOf && cond.left.typ != 0
|
|
||||||
&& cond.right is ast.IntegerLiteral {
|
|
||||||
// TODO: support struct.fieldname
|
|
||||||
s, _ := g.table.type_size(g.unwrap_generic(cond.left.typ))
|
|
||||||
right := cond.right as ast.IntegerLiteral
|
|
||||||
is_true := match cond.op {
|
|
||||||
.gt { s > right.val.i64() }
|
|
||||||
.lt { s < right.val.i64() }
|
|
||||||
.ge { s >= right.val.i64() }
|
|
||||||
.le { s <= right.val.i64() }
|
|
||||||
else { false }
|
|
||||||
}
|
|
||||||
if is_true {
|
|
||||||
g.write('1')
|
|
||||||
} else {
|
|
||||||
g.write('0')
|
|
||||||
}
|
|
||||||
return is_true, true
|
|
||||||
} else {
|
|
||||||
return true, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return true, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast.Ident {
|
|
||||||
ifdef := g.comptime_if_to_ifdef(cond.name, false) or { 'true' } // handled in checker
|
|
||||||
g.write('defined(${ifdef})')
|
|
||||||
return true, false
|
|
||||||
}
|
|
||||||
ast.ComptimeCall {
|
|
||||||
if cond.kind == .pkgconfig {
|
|
||||||
g.write('${pkg_exist}')
|
|
||||||
return true, false
|
|
||||||
}
|
|
||||||
if cond.kind == .d {
|
|
||||||
if cond.result_type == ast.bool_type {
|
|
||||||
if cond.compile_value == 'true' {
|
|
||||||
g.write('1')
|
|
||||||
} else {
|
|
||||||
g.write('0')
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
g.write('defined(CUSTOM_DEFINE_${cond.args_var})')
|
|
||||||
}
|
|
||||||
return true, false
|
|
||||||
}
|
|
||||||
return true, false
|
|
||||||
}
|
|
||||||
ast.SelectorExpr {
|
|
||||||
if g.comptime.comptime_for_field_var != '' && cond.expr is ast.Ident
|
|
||||||
&& cond.expr.name == g.comptime.comptime_for_field_var
|
|
||||||
&& cond.field_name in ['is_mut', 'is_pub', 'is_shared', 'is_atomic', 'is_option', 'is_array', 'is_map', 'is_chan', 'is_struct', 'is_alias', 'is_enum'] {
|
|
||||||
ret_bool := g.type_resolver.get_comptime_selector_bool_field(cond.field_name)
|
|
||||||
g.write(ret_bool.str())
|
|
||||||
return ret_bool, true
|
|
||||||
} else {
|
|
||||||
g.write('1')
|
|
||||||
return true, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// should be unreachable, but just in case
|
|
||||||
g.write('1')
|
|
||||||
return true, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// push_new_comptime_info saves the current comptime information
|
// push_new_comptime_info saves the current comptime information
|
||||||
fn (mut g Gen) push_new_comptime_info() {
|
fn (mut g Gen) push_new_comptime_info() {
|
||||||
g.type_resolver.info_stack << type_resolver.ResolverInfo{
|
g.type_resolver.info_stack << type_resolver.ResolverInfo{
|
||||||
|
@ -847,6 +568,8 @@ fn (mut g Gen) push_new_comptime_info() {
|
||||||
comptime_for_field_type: g.comptime.comptime_for_field_type
|
comptime_for_field_type: g.comptime.comptime_for_field_type
|
||||||
comptime_for_field_value: g.comptime.comptime_for_field_value
|
comptime_for_field_value: g.comptime.comptime_for_field_value
|
||||||
comptime_for_enum_var: g.comptime.comptime_for_enum_var
|
comptime_for_enum_var: g.comptime.comptime_for_enum_var
|
||||||
|
comptime_for_attr_var: g.comptime.comptime_for_attr_var
|
||||||
|
comptime_for_attr_value: g.comptime.comptime_for_attr_value
|
||||||
comptime_for_method_var: g.comptime.comptime_for_method_var
|
comptime_for_method_var: g.comptime.comptime_for_method_var
|
||||||
comptime_for_method: g.comptime.comptime_for_method
|
comptime_for_method: g.comptime.comptime_for_method
|
||||||
comptime_for_method_ret_type: g.comptime.comptime_for_method_ret_type
|
comptime_for_method_ret_type: g.comptime.comptime_for_method_ret_type
|
||||||
|
@ -864,6 +587,8 @@ fn (mut g Gen) pop_comptime_info() {
|
||||||
g.comptime.comptime_for_field_type = old.comptime_for_field_type
|
g.comptime.comptime_for_field_type = old.comptime_for_field_type
|
||||||
g.comptime.comptime_for_field_value = old.comptime_for_field_value
|
g.comptime.comptime_for_field_value = old.comptime_for_field_value
|
||||||
g.comptime.comptime_for_enum_var = old.comptime_for_enum_var
|
g.comptime.comptime_for_enum_var = old.comptime_for_enum_var
|
||||||
|
g.comptime.comptime_for_attr_var = old.comptime_for_attr_var
|
||||||
|
g.comptime.comptime_for_attr_value = old.comptime_for_attr_value
|
||||||
g.comptime.comptime_for_method_var = old.comptime_for_method_var
|
g.comptime.comptime_for_method_var = old.comptime_for_method_var
|
||||||
g.comptime.comptime_for_method = old.comptime_for_method
|
g.comptime.comptime_for_method = old.comptime_for_method
|
||||||
g.comptime.comptime_for_method_ret_type = old.comptime_for_method_ret_type
|
g.comptime.comptime_for_method_ret_type = old.comptime_for_method_ret_type
|
||||||
|
@ -887,6 +612,7 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) {
|
||||||
typ_vweb_result := g.table.find_type('vweb.Result')
|
typ_vweb_result := g.table.find_type('vweb.Result')
|
||||||
for method in methods {
|
for method in methods {
|
||||||
g.push_new_comptime_info()
|
g.push_new_comptime_info()
|
||||||
|
g.comptime.inside_comptime_for = true
|
||||||
// filter vweb route methods (non-generic method)
|
// filter vweb route methods (non-generic method)
|
||||||
if method.receiver_type != 0 && method.return_type == typ_vweb_result {
|
if method.receiver_type != 0 && method.return_type == typ_vweb_result {
|
||||||
rec_sym := g.table.sym(method.receiver_type)
|
rec_sym := g.table.sym(method.receiver_type)
|
||||||
|
@ -902,7 +628,7 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) {
|
||||||
}
|
}
|
||||||
g.comptime.comptime_for_method = unsafe { &method }
|
g.comptime.comptime_for_method = unsafe { &method }
|
||||||
g.comptime.comptime_for_method_var = node.val_var
|
g.comptime.comptime_for_method_var = node.val_var
|
||||||
g.writeln('/* method ${i} */ {')
|
g.writeln('/* method ${i} : ${method.name} */ {')
|
||||||
g.writeln('\t${node.val_var}.name = _S("${method.name}");')
|
g.writeln('\t${node.val_var}.name = _S("${method.name}");')
|
||||||
if method.attrs.len == 0 {
|
if method.attrs.len == 0 {
|
||||||
g.writeln('\t${node.val_var}.attrs = __new_array_with_default(0, 0, sizeof(string), 0);')
|
g.writeln('\t${node.val_var}.attrs = __new_array_with_default(0, 0, sizeof(string), 0);')
|
||||||
|
@ -976,13 +702,13 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) {
|
||||||
if fields.len > 0 {
|
if fields.len > 0 {
|
||||||
g.writeln('\tFieldData ${node.val_var} = {0};')
|
g.writeln('\tFieldData ${node.val_var} = {0};')
|
||||||
}
|
}
|
||||||
g.push_new_comptime_info()
|
|
||||||
for field in fields {
|
for field in fields {
|
||||||
|
g.push_new_comptime_info()
|
||||||
g.comptime.inside_comptime_for = true
|
g.comptime.inside_comptime_for = true
|
||||||
g.comptime.comptime_for_field_var = node.val_var
|
g.comptime.comptime_for_field_var = node.val_var
|
||||||
g.comptime.comptime_for_field_value = field
|
g.comptime.comptime_for_field_value = field
|
||||||
g.comptime.comptime_for_field_type = field.typ
|
g.comptime.comptime_for_field_type = field.typ
|
||||||
g.writeln('/* field ${i} */ {')
|
g.writeln('/* field ${i} : ${field.name} */ {')
|
||||||
g.writeln('\t${node.val_var}.name = _S("${field.name}");')
|
g.writeln('\t${node.val_var}.name = _S("${field.name}");')
|
||||||
if field.attrs.len == 0 {
|
if field.attrs.len == 0 {
|
||||||
g.writeln('\t${node.val_var}.attrs = __new_array_with_default(0, 0, sizeof(string), 0);')
|
g.writeln('\t${node.val_var}.attrs = __new_array_with_default(0, 0, sizeof(string), 0);')
|
||||||
|
@ -996,8 +722,8 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) {
|
||||||
styp := field.typ
|
styp := field.typ
|
||||||
unaliased_styp := g.table.unaliased_type(styp)
|
unaliased_styp := g.table.unaliased_type(styp)
|
||||||
|
|
||||||
g.writeln('\t${node.val_var}.typ = ${int(styp.idx())};')
|
g.writeln('\t${node.val_var}.typ = ${int(styp.idx())};\t// ${g.table.type_to_str(styp)}')
|
||||||
g.writeln('\t${node.val_var}.unaliased_typ = ${int(unaliased_styp.idx())};')
|
g.writeln('\t${node.val_var}.unaliased_typ = ${int(unaliased_styp.idx())};\t// ${g.table.type_to_str(unaliased_styp)}')
|
||||||
g.writeln('\t${node.val_var}.is_pub = ${field.is_pub};')
|
g.writeln('\t${node.val_var}.is_pub = ${field.is_pub};')
|
||||||
g.writeln('\t${node.val_var}.is_mut = ${field.is_mut};')
|
g.writeln('\t${node.val_var}.is_mut = ${field.is_mut};')
|
||||||
|
|
||||||
|
@ -1019,17 +745,18 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) {
|
||||||
g.stmts(node.stmts)
|
g.stmts(node.stmts)
|
||||||
i++
|
i++
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
}
|
|
||||||
g.pop_comptime_info()
|
g.pop_comptime_info()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if node.kind == .values {
|
} else if node.kind == .values {
|
||||||
if sym.kind == .enum {
|
if sym.kind == .enum {
|
||||||
if sym.info is ast.Enum {
|
if sym.info is ast.Enum {
|
||||||
if sym.info.vals.len > 0 {
|
if sym.info.vals.len > 0 {
|
||||||
g.writeln('\tEnumData ${node.val_var} = {0};')
|
g.writeln('\tEnumData ${node.val_var} = {0};')
|
||||||
}
|
}
|
||||||
g.push_new_comptime_info()
|
|
||||||
for val in sym.info.vals {
|
for val in sym.info.vals {
|
||||||
|
g.push_new_comptime_info()
|
||||||
|
g.comptime.inside_comptime_for = true
|
||||||
g.comptime.comptime_for_enum_var = node.val_var
|
g.comptime.comptime_for_enum_var = node.val_var
|
||||||
g.type_resolver.update_ct_type('${node.val_var}.typ', node.typ)
|
g.type_resolver.update_ct_type('${node.val_var}.typ', node.typ)
|
||||||
|
|
||||||
|
@ -1053,17 +780,21 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) {
|
||||||
g.stmts(node.stmts)
|
g.stmts(node.stmts)
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
i++
|
i++
|
||||||
}
|
|
||||||
g.pop_comptime_info()
|
g.pop_comptime_info()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if node.kind == .attributes {
|
} else if node.kind == .attributes {
|
||||||
attrs := g.table.get_attrs(sym)
|
attrs := g.table.get_attrs(sym)
|
||||||
if attrs.len > 0 {
|
if attrs.len > 0 {
|
||||||
g.writeln('\tVAttribute ${node.val_var} = {0};')
|
g.writeln('\tVAttribute ${node.val_var} = {0};')
|
||||||
|
|
||||||
for attr in attrs {
|
for attr in attrs {
|
||||||
g.writeln('/* attribute ${i} */ {')
|
g.push_new_comptime_info()
|
||||||
|
g.comptime.inside_comptime_for = true
|
||||||
|
g.comptime.comptime_for_attr_var = node.val_var
|
||||||
|
g.comptime.comptime_for_attr_value = attr
|
||||||
|
g.writeln('/* attribute ${i} : ${attr.name} */ {')
|
||||||
g.writeln('\t${node.val_var}.name = _S("${attr.name}");')
|
g.writeln('\t${node.val_var}.name = _S("${attr.name}");')
|
||||||
g.writeln('\t${node.val_var}.has_arg = ${attr.has_arg};')
|
g.writeln('\t${node.val_var}.has_arg = ${attr.has_arg};')
|
||||||
g.writeln('\t${node.val_var}.arg = _S("${util.smart_quote(attr.arg, false)}");')
|
g.writeln('\t${node.val_var}.arg = _S("${util.smart_quote(attr.arg, false)}");')
|
||||||
|
@ -1071,6 +802,7 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) {
|
||||||
g.stmts(node.stmts)
|
g.stmts(node.stmts)
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
i++
|
i++
|
||||||
|
g.pop_comptime_info()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if node.kind == .variants {
|
} else if node.kind == .variants {
|
||||||
|
@ -1079,40 +811,41 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) {
|
||||||
g.writeln('\tVariantData ${node.val_var} = {0};')
|
g.writeln('\tVariantData ${node.val_var} = {0};')
|
||||||
}
|
}
|
||||||
g.comptime.inside_comptime_for = true
|
g.comptime.inside_comptime_for = true
|
||||||
g.push_new_comptime_info()
|
|
||||||
for variant in sym.info.variants {
|
for variant in sym.info.variants {
|
||||||
|
g.push_new_comptime_info()
|
||||||
|
g.comptime.inside_comptime_for = true
|
||||||
g.comptime.comptime_for_variant_var = node.val_var
|
g.comptime.comptime_for_variant_var = node.val_var
|
||||||
g.type_resolver.update_ct_type('${node.val_var}.typ', variant)
|
g.type_resolver.update_ct_type('${node.val_var}.typ', variant)
|
||||||
|
|
||||||
g.writeln('/* variant ${i} */ {')
|
g.writeln('/* variant ${i} : ${g.table.type_to_str(variant)} */ {')
|
||||||
g.writeln('\t${node.val_var}.typ = ${int(variant)};')
|
g.writeln('\t${node.val_var}.typ = ${int(variant)};\t// ')
|
||||||
g.stmts(node.stmts)
|
g.stmts(node.stmts)
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
i++
|
i++
|
||||||
}
|
|
||||||
g.pop_comptime_info()
|
g.pop_comptime_info()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if node.kind == .params {
|
} else if node.kind == .params {
|
||||||
method := g.comptime.comptime_for_method
|
method := g.comptime.comptime_for_method
|
||||||
|
|
||||||
if method.params.len > 0 {
|
if method.params.len > 0 {
|
||||||
g.writeln('\tMethodParam ${node.val_var} = {0};')
|
g.writeln('\tMethodParam ${node.val_var} = {0};')
|
||||||
}
|
}
|
||||||
|
for param in method.params[1..] {
|
||||||
g.push_new_comptime_info()
|
g.push_new_comptime_info()
|
||||||
g.comptime.inside_comptime_for = true
|
g.comptime.inside_comptime_for = true
|
||||||
g.comptime.comptime_for_method_param_var = node.val_var
|
g.comptime.comptime_for_method_param_var = node.val_var
|
||||||
for param in method.params[1..] {
|
|
||||||
g.type_resolver.update_ct_type('${node.val_var}.typ', param.typ)
|
g.type_resolver.update_ct_type('${node.val_var}.typ', param.typ)
|
||||||
|
|
||||||
g.writeln('/* method param ${i} */ {')
|
g.writeln('/* method param ${i} : ${param.name} */ {')
|
||||||
g.writeln('\t${node.val_var}.typ = ${int(param.typ)};')
|
g.writeln('\t${node.val_var}.typ = ${int(param.typ)};\t// ${g.table.type_to_str(param.typ)}')
|
||||||
g.writeln('\t${node.val_var}.name = _S("${param.name}");')
|
g.writeln('\t${node.val_var}.name = _S("${param.name}");')
|
||||||
g.stmts(node.stmts)
|
g.stmts(node.stmts)
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
i++
|
i++
|
||||||
}
|
|
||||||
g.pop_comptime_info()
|
g.pop_comptime_info()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
g.indent--
|
g.indent--
|
||||||
g.writeln('}// \$for')
|
g.writeln('}// \$for')
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,24 @@
|
||||||
module js
|
module js
|
||||||
|
|
||||||
|
import v.token
|
||||||
import v.ast
|
import v.ast
|
||||||
|
|
||||||
|
fn (mut g JsGen) gen_branch_context_string() string {
|
||||||
|
mut arr := []string{}
|
||||||
|
|
||||||
|
// gen `T=int,X=string`
|
||||||
|
if g.fn_decl != unsafe { nil } && g.fn_decl.generic_names.len > 0
|
||||||
|
&& g.fn_decl.generic_names.len == g.cur_concrete_types.len {
|
||||||
|
for i in 0 .. g.fn_decl.generic_names.len {
|
||||||
|
arr << g.fn_decl.generic_names[i] + '=' +
|
||||||
|
g.table.type_to_str(g.cur_concrete_types[i]).replace('main.', '')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: support comptime `$for`
|
||||||
|
return arr.join(',')
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut g JsGen) comptime_if(node ast.IfExpr) {
|
fn (mut g JsGen) comptime_if(node ast.IfExpr) {
|
||||||
if !node.is_expr && !node.has_else && node.branches.len == 1 {
|
if !node.is_expr && !node.has_else && node.branches.len == 1 {
|
||||||
if node.branches[0].stmts.len == 0 {
|
if node.branches[0].stmts.len == 0 {
|
||||||
|
@ -10,17 +27,32 @@ fn (mut g JsGen) comptime_if(node ast.IfExpr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mut comptime_branch_context_str := g.gen_branch_context_string()
|
||||||
|
mut is_true := ast.ComptTimeCondResult{}
|
||||||
for i, branch in node.branches {
|
for i, branch in node.branches {
|
||||||
|
idx_str := if branch.cond.pos() == token.Pos{} {
|
||||||
|
comptime_branch_context_str + '|${g.file.path}|${branch.pos}|'
|
||||||
|
} else {
|
||||||
|
comptime_branch_context_str + '|${g.file.path}|${branch.cond.pos()}|'
|
||||||
|
}
|
||||||
|
if comptime_is_true := g.table.comptime_is_true[idx_str] {
|
||||||
|
is_true = comptime_is_true
|
||||||
|
} else {
|
||||||
|
panic('checker error: cond result idx string not found => [${idx_str}]')
|
||||||
|
return
|
||||||
|
}
|
||||||
if i == node.branches.len - 1 && node.has_else {
|
if i == node.branches.len - 1 && node.has_else {
|
||||||
g.writeln('else')
|
g.writeln('else')
|
||||||
} else {
|
} else {
|
||||||
|
result := if is_true.val { '1' } else { '0' }
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
g.write('if (')
|
g.writeln('if (${result})')
|
||||||
} else {
|
} else {
|
||||||
g.write('else if (')
|
g.writeln('else if (${result})')
|
||||||
|
}
|
||||||
|
$if debug_comptime_branch_context ? {
|
||||||
|
g.writeln('// ${node.branches[i].cond} generic=[${comptime_branch_context_str}]')
|
||||||
}
|
}
|
||||||
g.comptime_if_cond(branch.cond, branch.pkg_exist)
|
|
||||||
g.writeln(')')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if node.is_expr {
|
if node.is_expr {
|
||||||
|
@ -45,7 +77,9 @@ fn (mut g JsGen) comptime_if(node ast.IfExpr) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
g.writeln('{')
|
g.writeln('{')
|
||||||
|
if is_true.val {
|
||||||
g.stmts(branch.stmts)
|
g.stmts(branch.stmts)
|
||||||
|
}
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,36 +5,32 @@ module wasm
|
||||||
|
|
||||||
import v.ast
|
import v.ast
|
||||||
|
|
||||||
pub fn (mut g Gen) comptime_cond(cond ast.Expr, pkg_exists bool) bool {
|
pub fn (mut g Gen) comptime_cond(cond ast.Expr) bool {
|
||||||
match cond {
|
match cond {
|
||||||
ast.BoolLiteral {
|
ast.BoolLiteral {
|
||||||
return cond.val
|
return cond.val
|
||||||
}
|
}
|
||||||
ast.ParExpr {
|
ast.ParExpr {
|
||||||
g.comptime_cond(cond.expr, pkg_exists)
|
g.comptime_cond(cond.expr)
|
||||||
}
|
}
|
||||||
ast.PrefixExpr {
|
ast.PrefixExpr {
|
||||||
if cond.op == .not {
|
if cond.op == .not {
|
||||||
return !g.comptime_cond(cond.right, pkg_exists)
|
return !g.comptime_cond(cond.right)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.InfixExpr {
|
ast.InfixExpr {
|
||||||
match cond.op {
|
match cond.op {
|
||||||
.and {
|
.and {
|
||||||
return g.comptime_cond(cond.left, pkg_exists)
|
return g.comptime_cond(cond.left) && g.comptime_cond(cond.right)
|
||||||
&& g.comptime_cond(cond.right, pkg_exists)
|
|
||||||
}
|
}
|
||||||
.logical_or {
|
.logical_or {
|
||||||
return g.comptime_cond(cond.left, pkg_exists)
|
return g.comptime_cond(cond.left) || g.comptime_cond(cond.right)
|
||||||
|| g.comptime_cond(cond.right, pkg_exists)
|
|
||||||
}
|
}
|
||||||
.eq {
|
.eq {
|
||||||
return g.comptime_cond(cond.left, pkg_exists) == g.comptime_cond(cond.right,
|
return g.comptime_cond(cond.left) == g.comptime_cond(cond.right)
|
||||||
pkg_exists)
|
|
||||||
}
|
}
|
||||||
.ne {
|
.ne {
|
||||||
return g.comptime_cond(cond.left, pkg_exists) != g.comptime_cond(cond.right,
|
return g.comptime_cond(cond.left) != g.comptime_cond(cond.right)
|
||||||
pkg_exists)
|
|
||||||
}
|
}
|
||||||
// wasm doesn't support generics
|
// wasm doesn't support generics
|
||||||
// .key_is, .not_is
|
// .key_is, .not_is
|
||||||
|
@ -45,7 +41,7 @@ pub fn (mut g Gen) comptime_cond(cond ast.Expr, pkg_exists bool) bool {
|
||||||
return g.comptime_if_to_ifdef(cond.name, false)
|
return g.comptime_if_to_ifdef(cond.name, false)
|
||||||
}
|
}
|
||||||
ast.ComptimeCall {
|
ast.ComptimeCall {
|
||||||
return pkg_exists // more documentation needed here...
|
return false // pkg_exists, more documentation needed here...
|
||||||
}
|
}
|
||||||
ast.PostfixExpr {
|
ast.PostfixExpr {
|
||||||
return g.comptime_if_to_ifdef((cond.expr as ast.Ident).name, true)
|
return g.comptime_if_to_ifdef((cond.expr as ast.Ident).name, true)
|
||||||
|
@ -66,7 +62,7 @@ pub fn (mut g Gen) comptime_if_expr(node ast.IfExpr, expected ast.Type, existing
|
||||||
for i, branch in node.branches {
|
for i, branch in node.branches {
|
||||||
has_expr := !(node.has_else && i + 1 >= node.branches.len)
|
has_expr := !(node.has_else && i + 1 >= node.branches.len)
|
||||||
|
|
||||||
if has_expr && !g.comptime_cond(branch.cond, branch.pkg_exist) {
|
if has_expr && !g.comptime_cond(branch.cond) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// !node.is_expr || cond
|
// !node.is_expr || cond
|
||||||
|
|
|
@ -4,9 +4,11 @@ const disable_opt_features = true
|
||||||
// Note: the `unknown_fn()` calls are here on purpose, to make sure that anything
|
// Note: the `unknown_fn()` calls are here on purpose, to make sure that anything
|
||||||
// that doesn't match a compile-time condition is not even parsed.
|
// that doesn't match a compile-time condition is not even parsed.
|
||||||
fn test_ct_expressions() {
|
fn test_ct_expressions() {
|
||||||
|
mut result := ''
|
||||||
foo := version
|
foo := version
|
||||||
bar := foo
|
bar := foo
|
||||||
$if bar == 123 {
|
$if bar == 123 {
|
||||||
|
result += 'a'
|
||||||
assert true
|
assert true
|
||||||
} $else {
|
} $else {
|
||||||
unknown_fn()
|
unknown_fn()
|
||||||
|
@ -15,6 +17,7 @@ fn test_ct_expressions() {
|
||||||
$if bar != 123 {
|
$if bar != 123 {
|
||||||
unknown_fn()
|
unknown_fn()
|
||||||
} $else $if bar != 124 {
|
} $else $if bar != 124 {
|
||||||
|
result += 'b'
|
||||||
assert true
|
assert true
|
||||||
} $else {
|
} $else {
|
||||||
unknown_fn()
|
unknown_fn()
|
||||||
|
@ -23,8 +26,10 @@ fn test_ct_expressions() {
|
||||||
$if !disable_opt_features {
|
$if !disable_opt_features {
|
||||||
unknown_fn()
|
unknown_fn()
|
||||||
} $else {
|
} $else {
|
||||||
|
result += 'c'
|
||||||
assert true
|
assert true
|
||||||
}
|
}
|
||||||
|
assert result == 'abc'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generic_t_is[O]() O {
|
fn generic_t_is[O]() O {
|
||||||
|
|
|
@ -30,7 +30,7 @@ fn test[T](val T) string {
|
||||||
|
|
||||||
fn test_main() {
|
fn test_main() {
|
||||||
assert test(u32(7)) == 'else block'
|
assert test(u32(7)) == 'else block'
|
||||||
assert test(OtherStruct{'7'}) == 'struct field string'
|
assert test(OtherStruct{'7'}) == 'not u32 or i32 struct field, got type: string'
|
||||||
assert test(I32Struct{-7}) == 'struct field i32'
|
assert test(I32Struct{-7}) == 'struct field i32'
|
||||||
assert test(U32Struct{7}) == 'struct field u32'
|
assert test(U32Struct{7}) == 'struct field u32'
|
||||||
}
|
}
|
||||||
|
|
34
vlib/v/tests/comptime/comptime_test_ident_test.v
Normal file
34
vlib/v/tests/comptime/comptime_test_ident_test.v
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
fn test_test_ident() {
|
||||||
|
mut result := ''
|
||||||
|
$if test ? {
|
||||||
|
result += '1'
|
||||||
|
} $else {
|
||||||
|
result += '2'
|
||||||
|
}
|
||||||
|
|
||||||
|
$if test {
|
||||||
|
result += '3'
|
||||||
|
} $else {
|
||||||
|
result += '4'
|
||||||
|
}
|
||||||
|
|
||||||
|
$if !test {
|
||||||
|
result += '5'
|
||||||
|
} $else {
|
||||||
|
result += '6'
|
||||||
|
}
|
||||||
|
|
||||||
|
$if $d('test', false) {
|
||||||
|
result += '7'
|
||||||
|
} $else {
|
||||||
|
result += '8'
|
||||||
|
}
|
||||||
|
|
||||||
|
$if $d('test', true) {
|
||||||
|
result += '9'
|
||||||
|
} $else {
|
||||||
|
result += '0'
|
||||||
|
}
|
||||||
|
|
||||||
|
assert result == '23689'
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue