mirror of
https://github.com/vlang/v.git
synced 2025-09-22 11:57:33 -04:00
This commit is contained in:
parent
89a24958a1
commit
d2174e47a5
@ -17,8 +17,16 @@ pub const max_i32 = i32(2147483647)
|
||||
pub const min_i64 = i64(-9223372036854775807 - 1)
|
||||
pub const max_i64 = i64(9223372036854775807)
|
||||
|
||||
pub const min_int = int(min_i32)
|
||||
pub const max_int = int(max_i32)
|
||||
pub const min_int = $if new_int ? && (arm64 || amd64 || rv64 || s390x || ppc64le || loongarch64) {
|
||||
int(min_i64)
|
||||
} $else {
|
||||
int(min_i32)
|
||||
}
|
||||
pub const max_int = $if new_int ? && (arm64 || amd64 || rv64 || s390x || ppc64le || loongarch64) {
|
||||
int(max_i64)
|
||||
} $else {
|
||||
int(max_i32)
|
||||
}
|
||||
|
||||
pub const min_u8 = u8(0)
|
||||
pub const max_u8 = u8(255)
|
||||
|
@ -18,334 +18,15 @@ fn (mut g JsGen) gen_branch_context_string() string {
|
||||
return arr.join(',')
|
||||
}
|
||||
|
||||
fn (mut g JsGen) comptime_if(node ast.IfExpr) {
|
||||
if !node.is_expr && !node.has_else && node.branches.len == 1 {
|
||||
if node.branches[0].stmts.len == 0 {
|
||||
// empty ifdef; result of target OS != conditional => skip
|
||||
return
|
||||
}
|
||||
fn (mut g JsGen) comptime_if_result(branch ast.IfBranch) bool {
|
||||
idx_str := g.gen_branch_context_string() + '|id=${branch.id}|'
|
||||
$if debug_comptime_branch_context ? {
|
||||
g.write('/* ${idx_str} */')
|
||||
}
|
||||
|
||||
mut comptime_branch_context_str := g.gen_branch_context_string()
|
||||
mut is_true := ast.ComptTimeCondResult{}
|
||||
for i, branch in node.branches {
|
||||
idx_str := comptime_branch_context_str + '|id=${branch.id}|'
|
||||
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 {
|
||||
g.writeln('else')
|
||||
} else {
|
||||
result := if is_true.val { '1' } else { '0' }
|
||||
if i == 0 {
|
||||
g.writeln('if (${result})')
|
||||
} else {
|
||||
g.writeln('else if (${result})')
|
||||
}
|
||||
$if debug_comptime_branch_context ? {
|
||||
g.writeln('// ${node.branches[i].cond} generic=[${comptime_branch_context_str}]')
|
||||
}
|
||||
}
|
||||
|
||||
if node.is_expr {
|
||||
print('${branch.stmts}')
|
||||
len := branch.stmts.len
|
||||
if len > 0 {
|
||||
last := branch.stmts.last() as ast.ExprStmt
|
||||
if len > 1 {
|
||||
tmp := g.new_tmp_var()
|
||||
g.inc_indent()
|
||||
g.writeln('let ${tmp};')
|
||||
g.writeln('{')
|
||||
g.stmts(branch.stmts[..len - 1])
|
||||
g.write('\t${tmp} = ')
|
||||
g.stmt(last)
|
||||
g.writeln('}')
|
||||
g.dec_indent()
|
||||
g.writeln('${tmp};')
|
||||
} else {
|
||||
g.stmt(last)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
g.writeln('{')
|
||||
if is_true.val {
|
||||
g.stmts(branch.stmts)
|
||||
}
|
||||
g.writeln('}')
|
||||
}
|
||||
if comptime_is_true := g.table.comptime_is_true[idx_str] {
|
||||
return comptime_is_true.val
|
||||
} else {
|
||||
panic('checker error: cond result idx string not found => [${idx_str}]')
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// returning `false` means the statements inside the $if can be skipped
|
||||
*/
|
||||
// returns the value of the bool comptime expression
|
||||
fn (mut g JsGen) comptime_if_cond(cond ast.Expr, pkg_exist bool) bool {
|
||||
match cond {
|
||||
ast.BoolLiteral {
|
||||
g.expr(cond)
|
||||
return true
|
||||
}
|
||||
ast.ParExpr {
|
||||
g.write('(')
|
||||
is_cond_true := g.comptime_if_cond(cond.expr, pkg_exist)
|
||||
g.write(')')
|
||||
return is_cond_true
|
||||
}
|
||||
ast.PrefixExpr {
|
||||
g.write(cond.op.str())
|
||||
return g.comptime_if_cond(cond.right, pkg_exist)
|
||||
}
|
||||
ast.PostfixExpr {
|
||||
ifdef := g.comptime_if_to_ifdef((cond.expr as ast.Ident).name, true) or {
|
||||
verror(err.msg())
|
||||
return false
|
||||
}
|
||||
g.write('${ifdef}')
|
||||
return true
|
||||
}
|
||||
ast.InfixExpr {
|
||||
match cond.op {
|
||||
.and, .logical_or {
|
||||
l := g.comptime_if_cond(cond.left, pkg_exist)
|
||||
g.write(' ${cond.op} ')
|
||||
r := g.comptime_if_cond(cond.right, pkg_exist)
|
||||
return if cond.op == .and { l && r } else { l || r }
|
||||
}
|
||||
.key_is, .not_is {
|
||||
left := cond.left
|
||||
mut name := ''
|
||||
mut exp_type := ast.no_type
|
||||
got_type := (cond.right as ast.TypeNode).typ
|
||||
// Handle `$if x is Interface {`
|
||||
// mut matches_interface := 'false'
|
||||
if left is ast.TypeNode && cond.right is ast.TypeNode
|
||||
&& g.table.sym(got_type).kind == .interface {
|
||||
// `$if Foo is Interface {`
|
||||
interface_sym := g.table.sym(got_type)
|
||||
if interface_sym.info is ast.Interface {
|
||||
// q := g.table.sym(interface_sym.info.types[0])
|
||||
checked_type := g.unwrap_generic(left.typ)
|
||||
// TODO: PERF this check is run twice (also in the checker)
|
||||
// store the result in a field
|
||||
is_true := g.table.does_type_implement_interface(checked_type,
|
||||
got_type)
|
||||
// true // exp_type in interface_sym.info.types
|
||||
if cond.op == .key_is {
|
||||
if is_true {
|
||||
g.write('1')
|
||||
} else {
|
||||
g.write('0')
|
||||
}
|
||||
return is_true
|
||||
} else if cond.op == .not_is {
|
||||
if is_true {
|
||||
g.write('0')
|
||||
} else {
|
||||
g.write('1')
|
||||
}
|
||||
return !is_true
|
||||
}
|
||||
// matches_interface = '/*iface:$got_type $exp_type*/ true'
|
||||
//}
|
||||
}
|
||||
} else if left is ast.SelectorExpr {
|
||||
name = '${left.expr}.${left.field_name}'
|
||||
exp_type = g.comptime_var_type_map[name]
|
||||
} else if left is ast.TypeNode {
|
||||
// this is only allowed for generics currently, otherwise blocked by checker
|
||||
exp_type = g.unwrap_generic(left.typ)
|
||||
}
|
||||
|
||||
if cond.op == .key_is {
|
||||
g.write('${exp_type} == ${got_type}')
|
||||
return exp_type == got_type
|
||||
} else {
|
||||
g.write('${exp_type} != ${got_type}')
|
||||
return exp_type != got_type
|
||||
}
|
||||
}
|
||||
.eq, .ne {
|
||||
// TODO: Implement `$if method.args.len == 1`
|
||||
g.write('1')
|
||||
return true
|
||||
}
|
||||
else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
ast.Ident {
|
||||
ifdef := g.comptime_if_to_ifdef(cond.name, false) or { 'true' } // handled in checker
|
||||
g.write('${ifdef}')
|
||||
return true
|
||||
}
|
||||
ast.ComptimeCall {
|
||||
g.write('${pkg_exist}')
|
||||
return true
|
||||
}
|
||||
else {
|
||||
// should be unreachable, but just in case
|
||||
g.write('1')
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g JsGen) comptime_if_to_ifdef(name string, is_comptime_option bool) !string {
|
||||
match name {
|
||||
// platforms/os-es:
|
||||
'windows' {
|
||||
return '(\$process.platform == "windows")'
|
||||
}
|
||||
'ios' {
|
||||
return '(\$process.platform == "darwin")'
|
||||
}
|
||||
'macos' {
|
||||
return '(\$process.platform == "darwin")'
|
||||
}
|
||||
'mach' {
|
||||
return '(\$process.platform == "darwin")'
|
||||
}
|
||||
'darwin' {
|
||||
return '(\$process.platform == "darwin")'
|
||||
}
|
||||
'linux' {
|
||||
return '(\$process.platform == "linux")'
|
||||
}
|
||||
'freebsd' {
|
||||
return '(\$process.platform == "freebsd")'
|
||||
}
|
||||
'openbsd' {
|
||||
return '(\$process.platform == "openbsd")'
|
||||
}
|
||||
'bsd' {
|
||||
return '(\$process.platform == "freebsd" || (\$process.platform == "openbsd"))'
|
||||
}
|
||||
'android' {
|
||||
return '(\$process.platform == "android")'
|
||||
}
|
||||
'solaris' {
|
||||
return '(\$process.platform == "sunos")'
|
||||
}
|
||||
'js_node' {
|
||||
if g.pref.backend == .js_node {
|
||||
return 'true'
|
||||
} else {
|
||||
return 'false'
|
||||
}
|
||||
}
|
||||
'js_freestanding' {
|
||||
if g.pref.backend == .js_freestanding {
|
||||
return 'true'
|
||||
} else {
|
||||
return 'false'
|
||||
}
|
||||
}
|
||||
'js_browser' {
|
||||
if g.pref.backend == .js_browser {
|
||||
return 'true'
|
||||
} else {
|
||||
return 'false'
|
||||
}
|
||||
}
|
||||
'es5' {
|
||||
if g.pref.output_es5 {
|
||||
return 'true'
|
||||
} else {
|
||||
return 'false'
|
||||
}
|
||||
}
|
||||
//
|
||||
'js' {
|
||||
return 'true'
|
||||
}
|
||||
'native' {
|
||||
return 'false'
|
||||
}
|
||||
// compilers:
|
||||
'gcc' {
|
||||
return 'false'
|
||||
}
|
||||
'tinyc' {
|
||||
return 'false'
|
||||
}
|
||||
'clang' {
|
||||
return 'false'
|
||||
}
|
||||
'mingw' {
|
||||
return 'false'
|
||||
}
|
||||
'msvc' {
|
||||
return 'false'
|
||||
}
|
||||
'cplusplus' {
|
||||
return 'false'
|
||||
}
|
||||
// other:
|
||||
'threads' {
|
||||
return 'false'
|
||||
}
|
||||
'gcboehm' {
|
||||
return 'false'
|
||||
}
|
||||
// todo(playX): these should return true or false depending on CLI options
|
||||
'debug' {
|
||||
return 'false'
|
||||
}
|
||||
'prod' {
|
||||
return 'false'
|
||||
}
|
||||
'test' {
|
||||
return 'false'
|
||||
}
|
||||
'glibc' {
|
||||
return 'false'
|
||||
}
|
||||
'prealloc' {
|
||||
return 'false'
|
||||
}
|
||||
'no_bounds_checking' {
|
||||
return 'checkDefine("CUSTOM_DEFINE_no_bounds_checking")'
|
||||
}
|
||||
'freestanding' {
|
||||
return '_VFREESTANDING'
|
||||
}
|
||||
'autofree' {
|
||||
return '_VAUTOFREE'
|
||||
}
|
||||
// architectures:
|
||||
'amd64' {
|
||||
return '(\$process.arch == "x64")'
|
||||
}
|
||||
'aarch64', 'arm64' {
|
||||
return '(\$process.arch == "arm64)'
|
||||
}
|
||||
// bitness:
|
||||
'x64' {
|
||||
return '(\$process.arch == "x64")'
|
||||
}
|
||||
'x32' {
|
||||
return '(\$process.arch == "x32")'
|
||||
}
|
||||
// endianness:
|
||||
'little_endian' {
|
||||
return '(\$os.endianness == "LE")'
|
||||
}
|
||||
'big_endian' {
|
||||
return '(\$os.endianness == "BE")'
|
||||
}
|
||||
else {
|
||||
if is_comptime_option
|
||||
|| (g.pref.compile_defines_all.len > 0 && name in g.pref.compile_defines_all) {
|
||||
return 'checkDefine("CUSTOM_DEFINE_${name}")'
|
||||
}
|
||||
return error('bad os ifdef name "${name}"') // should never happen, caught in the checker
|
||||
}
|
||||
}
|
||||
return error('none')
|
||||
}
|
||||
|
@ -2722,10 +2722,6 @@ fn (mut g JsGen) need_tmp_var_in_if(node ast.IfExpr) bool {
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
|
||||
if node.is_comptime {
|
||||
g.comptime_if(node)
|
||||
return
|
||||
}
|
||||
// For simpe if expressions we can use C's `?:`
|
||||
// `if x > 0 { 1 } else { 2 }` => `(x > 0)? (1) : (2)`
|
||||
// For if expressions with multiple statements or another if expression inside, it's much
|
||||
@ -2734,6 +2730,8 @@ fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
|
||||
// Always use this in -autofree, since ?: can have tmp expressions that have to be freed.
|
||||
needs_tmp_var := g.need_tmp_var_in_if(node)
|
||||
tmp := if needs_tmp_var { g.new_tmp_var() } else { '' }
|
||||
mut is_true := false
|
||||
mut comptime_has_true_branch := false
|
||||
|
||||
if needs_tmp_var {
|
||||
if node.typ.has_flag(.option) {
|
||||
@ -2746,14 +2744,32 @@ fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
|
||||
prev := g.inside_ternary
|
||||
g.inside_ternary = true
|
||||
for i, branch in node.branches {
|
||||
if i > 0 {
|
||||
g.write(' : ')
|
||||
}
|
||||
if i < node.branches.len - 1 || !node.has_else {
|
||||
g.write('(')
|
||||
g.expr(branch.cond)
|
||||
g.write(').valueOf()')
|
||||
g.write(' ? ')
|
||||
if node.is_comptime {
|
||||
$if debug_comptime_branch_context ? {
|
||||
g.write('/* ${branch.cond} */')
|
||||
}
|
||||
// comptime $if, only generate the true branch
|
||||
if i < node.branches.len - 1 || !node.has_else {
|
||||
if !g.comptime_if_result(branch) {
|
||||
continue
|
||||
}
|
||||
comptime_has_true_branch = true
|
||||
} else {
|
||||
// else branch
|
||||
if comptime_has_true_branch {
|
||||
continue
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if i > 0 {
|
||||
g.write(' : ')
|
||||
}
|
||||
if i < node.branches.len - 1 || !node.has_else {
|
||||
g.write('(')
|
||||
g.expr(branch.cond)
|
||||
g.write(').valueOf()')
|
||||
g.write(' ? ')
|
||||
}
|
||||
}
|
||||
g.stmts(branch.stmts)
|
||||
}
|
||||
@ -2784,6 +2800,8 @@ fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
|
||||
}
|
||||
}
|
||||
|
||||
is_true = false
|
||||
comptime_has_true_branch = false
|
||||
for i, branch in node.branches {
|
||||
if i > 0 {
|
||||
g.write('} else ')
|
||||
@ -2796,6 +2814,9 @@ fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
|
||||
cvar_name := guard_vars[guard_idx]
|
||||
g.writeln('\tlet err = ${cvar_name}.err;')
|
||||
}
|
||||
if node.is_comptime && !comptime_has_true_branch {
|
||||
is_true = true
|
||||
}
|
||||
} else {
|
||||
match branch.cond {
|
||||
ast.IfGuardExpr {
|
||||
@ -2809,7 +2830,20 @@ fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
|
||||
g.writeln('if (${var_name}.state == 0) {')
|
||||
} else {
|
||||
g.write('if (${var_name} = ')
|
||||
g.expr(branch.cond.expr)
|
||||
if node.is_comptime {
|
||||
$if debug_comptime_branch_context ? {
|
||||
g.write('/* ${branch.cond} */')
|
||||
}
|
||||
is_true = g.comptime_if_result(branch)
|
||||
if is_true {
|
||||
g.write('1')
|
||||
comptime_has_true_branch = true
|
||||
} else {
|
||||
g.write('0')
|
||||
}
|
||||
} else {
|
||||
g.expr(branch.cond.expr)
|
||||
}
|
||||
g.writeln(', ${var_name}.state == 0) {')
|
||||
}
|
||||
if short_opt || branch.cond.vars[0].name != '_' {
|
||||
@ -2820,7 +2854,17 @@ fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
|
||||
branch.cond.vars[0].name
|
||||
}
|
||||
g.write('\tlet ${cond_var_name} = ')
|
||||
g.expr(branch.cond.expr)
|
||||
if node.is_comptime {
|
||||
is_true = g.comptime_if_result(branch)
|
||||
if is_true {
|
||||
g.write('1')
|
||||
comptime_has_true_branch = true
|
||||
} else {
|
||||
g.write('0')
|
||||
}
|
||||
} else {
|
||||
g.expr(branch.cond.expr)
|
||||
}
|
||||
g.writeln(';')
|
||||
} else {
|
||||
g.writeln('\tlet ${branch.cond.vars}[0].name = ${var_name}.data;')
|
||||
@ -2828,16 +2872,31 @@ fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
g.write('if ((')
|
||||
g.expr(branch.cond)
|
||||
g.writeln(').valueOf()) {')
|
||||
if node.is_comptime {
|
||||
g.write('if (')
|
||||
$if debug_comptime_branch_context ? {
|
||||
g.write('/* ${branch.cond} */')
|
||||
}
|
||||
is_true = g.comptime_if_result(branch)
|
||||
if is_true {
|
||||
g.write('1')
|
||||
comptime_has_true_branch = true
|
||||
} else {
|
||||
g.write('0')
|
||||
}
|
||||
g.writeln(') {')
|
||||
} else {
|
||||
g.write('if ((')
|
||||
g.expr(branch.cond)
|
||||
g.writeln(').valueOf()) {')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
g.inc_indent()
|
||||
if needs_tmp_var {
|
||||
g.stmts_with_tmp_var(branch.stmts, tmp)
|
||||
} else {
|
||||
} else if (node.is_comptime && is_true) || !node.is_comptime {
|
||||
g.stmts(branch.stmts)
|
||||
}
|
||||
g.dec_indent()
|
||||
|
Loading…
x
Reference in New Issue
Block a user