eval: add more infix op support; fix early func return (#24965)

This commit is contained in:
kbkpbot 2025-07-25 02:10:10 +08:00 committed by GitHub
parent a309593f56
commit af046e1c6e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 208 additions and 2 deletions

View File

@ -64,6 +64,7 @@ pub mut:
scope_idx int // this is increased when e.open_scope() is called, decreased when e.close_scope() (and all variables with that scope level deleted)
returning bool
return_values []Object
executed_return_stmt bool // already executed a return stmt in func
cur_mod string
cur_file string
@ -152,6 +153,7 @@ pub fn (mut e Eval) run_func(func ast.FnDecl, _args ...Object) {
scope_idx: e.scope_idx
}
}
e.executed_return_stmt = false
e.stmts(func.stmts)
e.returning = false
e.close_scope()
@ -317,6 +319,11 @@ pub fn (mut e Eval) comptime_cond(cond ast.Expr) bool {
}
}
}
ast.InfixExpr {
left := e.comptime_cond(cond.left)
right := e.comptime_cond(cond.right)
return e.infix_expr(left, right, cond.op, ast.bool_type) as bool
}
else {
e.error('unsupported expression')
}

View File

@ -498,6 +498,9 @@ pub fn (mut e Eval) expr(expr ast.Expr, expecting ast.Type) Object {
}
ast.PrefixExpr {
match expr.op {
.not {
return !(e.expr(expr.right, ast.bool_type) as bool)
}
.amp {
x := e.expr(expr.right, expr.right_type)
return Ptr{

View File

@ -6,6 +6,18 @@ import v.ast
fn (e &Eval) infix_expr(left Object, right Object, op token.Kind, expecting ast.Type) Object {
match op {
.and {
if left is bool && right is bool {
return left && right
}
e.error('invalid operands to &&: ${left.type_name()} and ${right.type_name()}')
}
.logical_or {
if left is bool && right is bool {
return left || right
}
e.error('invalid operands to ||: ${left.type_name()} and ${right.type_name()}')
}
.gt {
match left {
Int {
@ -120,6 +132,120 @@ fn (e &Eval) infix_expr(left Object, right Object, op token.Kind, expecting ast.
}
}
}
.ge {
match left {
Int {
match right {
Int { return left.val >= right.val }
Uint { return left.val >= right.val }
Float { return left.val >= right.val }
i64 { return left.val >= right }
f64 { return left.val >= right }
else { e.error('invalid operands to >=: Int and ${right.type_name()}') }
}
}
Uint {
match right {
Int { return left.val >= right.val }
Uint { return left.val >= right.val }
Float { return left.val >= right.val }
i64 { return left.val >= right }
f64 { return left.val >= right }
else { e.error('invalid operands to >=: Uint and ${right.type_name()}') }
}
}
Float {
match right {
Int { return left.val >= right.val }
Uint { return left.val >= right.val }
Float { return left.val >= right.val }
i64 { return left.val >= right }
f64 { return left.val >= right }
else { e.error('invalid operands to >=: Float and ${right.type_name()}') }
}
}
i64 {
match right {
Int { return left >= right.val }
Uint { return left >= right.val }
Float { return left >= right.val }
i64 { return left >= right }
f64 { return left >= right }
else { e.error('invalid operands to >=: int literal and ${right.type_name()}') }
}
}
f64 {
match right {
Int { return left >= right.val }
Uint { return left >= right.val }
Float { return left >= right.val }
i64 { return left >= right }
f64 { return left >= right }
else { e.error('invalid operands to >=: float literal and ${right.type_name()}') }
}
}
else {
e.error('invalid operands to >=: ${left.type_name()} and ${right.type_name()}')
}
}
}
.le {
match left {
Int {
match right {
Int { return left.val <= right.val }
Uint { return left.val <= right.val }
Float { return left.val <= right.val }
i64 { return left.val <= right }
f64 { return left.val <= right }
else { e.error('invalid operands to <=: Int and ${right.type_name()}') }
}
}
Uint {
match right {
Int { return left.val <= right.val }
Uint { return left.val <= right.val }
Float { return left.val <= right.val }
i64 { return left.val <= right }
f64 { return left.val <= right }
else { e.error('invalid operands to <=: Uint and ${right.type_name()}') }
}
}
Float {
match right {
Int { return left.val <= right.val }
Uint { return left.val <= right.val }
Float { return left.val <= right.val }
i64 { return left.val <= right }
f64 { return left.val <= right }
else { e.error('invalid operands to <=: Float and ${right.type_name()}') }
}
}
i64 {
match right {
Int { return left <= right.val }
Uint { return left <= right.val }
Float { return left <= right.val }
i64 { return left <= right }
f64 { return left <= right }
else { e.error('invalid operands to <=: int literal and ${right.type_name()}') }
}
}
f64 {
match right {
Int { return left <= right.val }
Uint { return left <= right.val }
Float { return left <= right.val }
i64 { return left <= right }
f64 { return left <= right }
else { e.error('invalid operands to <=: float literal and ${right.type_name()}') }
}
}
else {
e.error('invalid operands to <=: ${left.type_name()} and ${right.type_name()}')
}
}
}
.eq {
match left {
Int {

View File

@ -4,10 +4,16 @@ import v.ast
import v.token
pub fn (mut e Eval) stmts(stmts []ast.Stmt) {
if e.executed_return_stmt {
return
}
e.open_scope()
for stmt in stmts {
e.stmt(stmt)
if e.returning {
if !e.executed_return_stmt {
e.stmt(stmt)
}
if stmt is ast.Return {
e.executed_return_stmt = true
break
}
}

View File

@ -47,3 +47,24 @@ fn test_comptime_if_without_func() {
dump(ret)
assert ret == []
}
fn test_comptime_if_infix() {
mut e := eval.create()
ret := e.run('const a =
\$if amd64 || aarch64 || arm64 || rv64 { "64bit" }
\$else \$if i386 || arm32 || rv32 { "32bit" }
\$else \$if s390x { "s390x" }
\$else \$if ppc64le { "ppc64le" }
\$else \$if loongarch64 { "loongarch64" }
\$else { "unknown" }
const b = 1.5
fn display() (string,f64) { println(a) println(b) return a,b } display()')!
dump(ret)
assert ret[0].string().len != 0
assert ret[0].string() != 'unknown'
assert ret[1].float_val() == 1.5
}

View File

@ -29,3 +29,46 @@ fn test_if_return() {
dump(ret1)
assert ret1[0].int_val() == 666
}
fn test_if_infix_return_early() {
mut e := eval.create()
ret := e.run('
fn display(a int, b int) int {
mut k := false
if !k {
k = !k
}
println(k)
if a == 100 && b == 100 {
return 100
} else if a == 100 && b != 100 {
return 101
} else if a == 100 && b > 100 {
return 102
} else if a == 100 && b < 100 {
return 103
} else if a == 100 && b >= 100 {
return 104
} else if a == 100 && b <= 100 {
return 105
} else if a == 100 || b == 100 {
return 106
} else if a == 100 || b != 100 {
return 107
} else if a == 100 || b > 100 {
return 108
} else if a == 100 || b < 100 {
return 109
} else if a == 100 || b >= 100 {
return 110
} else if a == 100 || b <= 100 {
return 111
}
return 7171
}
display(200, 101)')!
dump(ret)
assert ret[0].int_val() == 107
}