eval: fix if-else; add infix op; fix func calls (#24972)

This commit is contained in:
kbkpbot 2025-07-25 22:45:31 +08:00 committed by GitHub
parent 38beb23c6a
commit e5eed5c5a4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 610 additions and 5 deletions

View File

@ -153,10 +153,14 @@ pub fn (mut e Eval) run_func(func ast.FnDecl, _args ...Object) {
scope_idx: e.scope_idx
}
}
prev_executed_return_stmt := e.executed_return_stmt
e.executed_return_stmt = false
e.returning = false
e.return_values = []
e.stmts(func.stmts)
e.returning = false
e.close_scope()
e.executed_return_stmt = prev_executed_return_stmt
e.scope_idx = old_scope
e.local_vars = e.local_vars_stack.pop()
}
@ -183,9 +187,12 @@ pub fn (mut e Eval) register_symbols(mut files []&ast.File) {
for _, field in fields {
e.returning = true
e.return_values = []
prev_executed_return_stmt := e.executed_return_stmt
e.executed_return_stmt = false
e.mods[mod][field.name.all_after_last('.')] = e.expr(field.expr, field.typ)
e.returning = false
e.return_values = []
e.executed_return_stmt = prev_executed_return_stmt
if mod == 'os' && field.name.all_after_last('.') == 'args' {
mut res := Array{}
res.val << e.pref.out_name.all_after_last('/')

View File

@ -111,10 +111,10 @@ pub fn (mut e Eval) expr(expr ast.Expr, expecting ast.Type) Object {
if func is ast.FnDecl {
e.run_func(func as ast.FnDecl, ...args)
if e.return_values.len == 1 {
return e.return_values[0]
return if e.return_values.len == 1 {
e.return_values[0]
} else {
return e.return_values
e.return_values
}
}
e.error('unknown function: ${mod}.${name} at line ${expr.pos.line_nr}')
@ -145,15 +145,16 @@ pub fn (mut e Eval) expr(expr ast.Expr, expecting ast.Type) Object {
}
ast.IfExpr {
for i, branch in expr.branches {
is_else_branch := expr.has_else && expr.branches.len == i + 1
result := if expr.is_comptime {
e.comptime_cond(branch.cond)
} else if expr.branches.len != i + 1 {
} else if !is_else_branch {
e.expr(branch.cond, ast.bool_type_idx) as bool
} else {
false
}
if result || expr.branches.len == i + 1 {
if result || is_else_branch {
stmts := branch.stmts.filter(it is ast.ExprStmt)
if stmts.len > 0 {
// a := if x == 1 { 100 } else { 200 }, we need to get expr result
@ -501,6 +502,38 @@ pub fn (mut e Eval) expr(expr ast.Expr, expecting ast.Type) Object {
.not {
return !(e.expr(expr.right, ast.bool_type) as bool)
}
.bit_not {
x := e.expr(expr.right, expr.right_type)
match x {
Uint {
return Uint{
val: ~x.val
size: x.size
}
}
Int {
return Int{
val: ~x.val
size: x.size
}
}
bool {
return !(x as bool)
}
i64 {
return ~(x as i64)
}
rune {
return ~(x as rune)
}
u8 {
return ~(x as u8)
}
else {
e.error('operator `~` can only be used with integer types: ${e.table.sym(expr.right_type).str()}')
}
}
}
.amp {
x := e.expr(expr.right, expr.right_type)
return Ptr{

View File

@ -372,6 +372,387 @@ fn (e &Eval) infix_expr(left Object, right Object, op token.Kind, expecting ast.
}
}
}
.amp {
match left {
Int {
match right {
Int {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left.val) & i64(right.val), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left.val) & u64(right.val), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left.val) & i64(right.val))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
Uint {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left.val) & i64(right.val), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left.val) & u64(right.val), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left.val) & i64(right.val))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
char, u8, i64 {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left.val) & i64(right), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left.val) & u64(right), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left.val) & i64(right))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
else {
e.error('invalid operands to &: Int and ${right.type_name()}')
}
}
}
Uint {
match right {
Int {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left.val) & i64(right.val), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left.val) & u64(right.val), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left.val) & i64(right.val))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
Uint {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left.val) & i64(right.val), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left.val) & u64(right.val), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left.val) & i64(right.val))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
char, u8, i64 {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left.val) & i64(right), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left.val) & u64(right), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left.val) & i64(right))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
else {
e.error('invalid operands to &: Uint and ${right.type_name()}')
}
}
}
char, u8, i64 {
match right {
Int {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left) & i64(right.val), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left) & u64(right.val), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left) & i64(right.val))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
Uint {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left) & i64(right.val), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left) & u64(right.val), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left) & i64(right.val))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
char, u8, i64 {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left) & i64(right), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left) & u64(right), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left) & i64(right))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
else {
e.error('invalid operands to &: ${left} and ${right.type_name()}')
}
}
}
else {
e.error('invalid operands to &: ${left} and ${right.type_name()}')
}
}
}
.pipe {
match left {
Int {
match right {
Int {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left.val) | i64(right.val), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left.val) | u64(right.val), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left.val) | i64(right.val))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
Uint {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left.val) | i64(right.val), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left.val) | u64(right.val), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left.val) | i64(right.val))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
char, u8, i64 {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left.val) | i64(right), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left.val) | u64(right), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left.val) | i64(right))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
else {
e.error('invalid operands to |: Int and ${right.type_name()}')
}
}
}
Uint {
match right {
Int {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left.val) | i64(right.val), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left.val) | u64(right.val), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left.val) | i64(right.val))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
Uint {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left.val) | i64(right.val), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left.val) | u64(right.val), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left.val) | i64(right.val))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
char, u8, i64 {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left.val) | i64(right), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left.val) | u64(right), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left.val) | i64(right))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
else {
e.error('invalid operands to |: Uint and ${right.type_name()}')
}
}
}
char, u8, i64 {
match right {
Int {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left) | i64(right.val), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left) | u64(right.val), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left) | i64(right.val))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
Uint {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left) | i64(right.val), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left) | u64(right.val), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left) | i64(right.val))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
char, u8, i64 {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left) | i64(right), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left) | u64(right), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left) | i64(right))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
else {
e.error('invalid operands to |: ${left} and ${right.type_name()}')
}
}
}
else {
e.error('invalid operands to |: ${left} and ${right.type_name()}')
}
}
}
.xor {
match left {
Int {
match right {
Int {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left.val) ^ i64(right.val), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left.val) ^ u64(right.val), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left.val) ^ i64(right.val))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
Uint {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left.val) ^ i64(right.val), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left.val) ^ u64(right.val), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left.val) ^ i64(right.val))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
char, u8, i64 {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left.val) ^ i64(right), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left.val) ^ u64(right), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left.val) ^ i64(right))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
else {
e.error('invalid operands to ^: Int and ${right.type_name()}')
}
}
}
Uint {
match right {
Int {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left.val) ^ i64(right.val), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left.val) ^ u64(right.val), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left.val) ^ i64(right.val))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
Uint {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left.val) ^ i64(right.val), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left.val) ^ u64(right.val), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left.val) ^ i64(right.val))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
char, u8, i64 {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left.val) ^ i64(right), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left.val) ^ u64(right), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left.val) ^ i64(right))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
else {
e.error('invalid operands to ^: Uint and ${right.type_name()}')
}
}
}
char, u8, i64 {
match right {
Int {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left) ^ i64(right.val), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left) ^ u64(right.val), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left) ^ i64(right.val))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
Uint {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left) ^ i64(right.val), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left) ^ u64(right.val), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left) ^ i64(right.val))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
char, u8, i64 {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left) ^ i64(right), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left) ^ u64(right), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left) ^ i64(right))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
else {
e.error('invalid operands to &: ${left} and ${right.type_name()}')
}
}
}
else {
e.error('invalid operands to ^: ${left} and ${right.type_name()}')
}
}
}
.plus {
match left {
Int {
@ -2040,6 +2421,133 @@ fn (e &Eval) infix_expr(left Object, right Object, op token.Kind, expecting ast.
}
}
}
.mod {
match left {
Int {
match right {
Int {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left.val) % i64(right.val), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left.val) % u64(right.val), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left.val) % i64(right.val))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
Uint {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left.val) % i64(right.val), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left.val) % u64(right.val), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left.val) % i64(right.val))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
i64 {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left.val) % i64(right), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left.val) % u64(right), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left.val) % i64(right))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
else {
e.error('invalid operands to %: Int and ${right.type_name()}')
}
}
}
Uint {
match right {
Int {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left.val) % i64(right.val), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left.val) % u64(right.val), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left.val) % i64(right.val))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
Uint {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left.val) % i64(right.val), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left.val) % u64(right.val), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left.val) % i64(right.val))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
i64 {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left.val) % i64(right), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left.val) % u64(right), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left.val) % i64(right))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
else {
e.error('invalid operands to %: Uint and ${right.type_name()}')
}
}
}
i64 {
match right {
Int {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left) % i64(right.val), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left) % u64(right.val), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left) % i64(right.val))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
Uint {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left) % i64(right.val), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left) % u64(right.val), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left) % i64(right.val))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
i64 {
if expecting in ast.signed_integer_type_idxs {
return Int{i64(left) % i64(right), i8(e.type_to_size(expecting))}
} else if expecting in ast.unsigned_integer_type_idxs {
return Uint{u64(left) % u64(right), i8(e.type_to_size(expecting))}
} else if expecting == ast.int_literal_type_idx {
return i64(i64(left) % i64(right))
} else {
e.error('unknown infix expectation: ${e.table.sym(expecting).str()}')
}
}
else {
e.error('invalid operands to %: int literal and ${right.type_name()}')
}
}
}
else {
e.error('invalid operands to %: ${left.type_name()} and ${right.type_name()}')
}
}
}
.right_shift {
match left {
Int {

View File

@ -72,6 +72,10 @@ pub fn (mut e Eval) stmt(stmt ast.Stmt) {
for i, expr in stmt.exprs {
e.return_values << e.expr(expr, stmt.types[i])
}
if e.return_values.len > stmt.exprs.len {
// keep only results
e.return_values.drop(e.return_values.len - stmt.exprs.len)
}
e.returning = old_returning
}
ast.ForInStmt {

View File

@ -0,0 +1,26 @@
import v.eval
fn test_func_return() {
mut e := eval.create()
ret := e.run('
fn sub(a int) int {
if a > 105 {
return 101
}
return 5151
}
fn key(b int) int {
println(b)
if b > 100 {
return 3 + sub(sub(sub(b)))
}
return 7171
}
key(110)')!
dump(ret)
assert ret[0].int_val() == 104
}

View File

@ -72,3 +72,30 @@ fn test_if_infix_return_early() {
dump(ret)
assert ret[0].int_val() == 107
}
fn test_if_infix_op() {
mut e := eval.create()
ret := e.run('
fn display(a int, b int) int {
mut k := false
if !k {
k = !k
}
println(k)
mut data := u64(0xFFFF0000)
mut c := u8(0xFF)
if c & data == c {
return 3131
}
if ((data & 0xFFFF0000) | (0x3FFF ^ data)) == 0x66111 {
println(data)
return 6060
}
return 7171
}
display(200, 101)')!
dump(ret)
assert ret[0].int_val() == 7171
}