Skip to content

Commit af046e1

Browse files
authored
eval: add more infix op support; fix early func return (#24965)
1 parent a309593 commit af046e1

6 files changed

Lines changed: 208 additions & 2 deletions

File tree

‎vlib/v/eval/eval.v‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ pub mut:
6464
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)
6565
returning bool
6666
return_values []Object
67+
executed_return_stmt bool // already executed a return stmt in func
6768
cur_mod string
6869
cur_file string
6970

@@ -152,6 +153,7 @@ pub fn (mut e Eval) run_func(func ast.FnDecl, _args ...Object) {
152153
scope_idx: e.scope_idx
153154
}
154155
}
156+
e.executed_return_stmt = false
155157
e.stmts(func.stmts)
156158
e.returning = false
157159
e.close_scope()
@@ -317,6 +319,11 @@ pub fn (mut e Eval) comptime_cond(cond ast.Expr) bool {
317319
}
318320
}
319321
}
322+
ast.InfixExpr {
323+
left := e.comptime_cond(cond.left)
324+
right := e.comptime_cond(cond.right)
325+
return e.infix_expr(left, right, cond.op, ast.bool_type) as bool
326+
}
320327
else {
321328
e.error('unsupported expression')
322329
}

‎vlib/v/eval/expr.c.v‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,9 @@ pub fn (mut e Eval) expr(expr ast.Expr, expecting ast.Type) Object {
498498
}
499499
ast.PrefixExpr {
500500
match expr.op {
501+
.not {
502+
return !(e.expr(expr.right, ast.bool_type) as bool)
503+
}
501504
.amp {
502505
x := e.expr(expr.right, expr.right_type)
503506
return Ptr{

‎vlib/v/eval/infix.v‎

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,18 @@ import v.ast
66

77
fn (e &Eval) infix_expr(left Object, right Object, op token.Kind, expecting ast.Type) Object {
88
match op {
9+
.and {
10+
if left is bool && right is bool {
11+
return left && right
12+
}
13+
e.error('invalid operands to &&: ${left.type_name()} and ${right.type_name()}')
14+
}
15+
.logical_or {
16+
if left is bool && right is bool {
17+
return left || right
18+
}
19+
e.error('invalid operands to ||: ${left.type_name()} and ${right.type_name()}')
20+
}
921
.gt {
1022
match left {
1123
Int {
@@ -120,6 +132,120 @@ fn (e &Eval) infix_expr(left Object, right Object, op token.Kind, expecting ast.
120132
}
121133
}
122134
}
135+
.ge {
136+
match left {
137+
Int {
138+
match right {
139+
Int { return left.val >= right.val }
140+
Uint { return left.val >= right.val }
141+
Float { return left.val >= right.val }
142+
i64 { return left.val >= right }
143+
f64 { return left.val >= right }
144+
else { e.error('invalid operands to >=: Int and ${right.type_name()}') }
145+
}
146+
}
147+
Uint {
148+
match right {
149+
Int { return left.val >= right.val }
150+
Uint { return left.val >= right.val }
151+
Float { return left.val >= right.val }
152+
i64 { return left.val >= right }
153+
f64 { return left.val >= right }
154+
else { e.error('invalid operands to >=: Uint and ${right.type_name()}') }
155+
}
156+
}
157+
Float {
158+
match right {
159+
Int { return left.val >= right.val }
160+
Uint { return left.val >= right.val }
161+
Float { return left.val >= right.val }
162+
i64 { return left.val >= right }
163+
f64 { return left.val >= right }
164+
else { e.error('invalid operands to >=: Float and ${right.type_name()}') }
165+
}
166+
}
167+
i64 {
168+
match right {
169+
Int { return left >= right.val }
170+
Uint { return left >= right.val }
171+
Float { return left >= right.val }
172+
i64 { return left >= right }
173+
f64 { return left >= right }
174+
else { e.error('invalid operands to >=: int literal and ${right.type_name()}') }
175+
}
176+
}
177+
f64 {
178+
match right {
179+
Int { return left >= right.val }
180+
Uint { return left >= right.val }
181+
Float { return left >= right.val }
182+
i64 { return left >= right }
183+
f64 { return left >= right }
184+
else { e.error('invalid operands to >=: float literal and ${right.type_name()}') }
185+
}
186+
}
187+
else {
188+
e.error('invalid operands to >=: ${left.type_name()} and ${right.type_name()}')
189+
}
190+
}
191+
}
192+
.le {
193+
match left {
194+
Int {
195+
match right {
196+
Int { return left.val <= right.val }
197+
Uint { return left.val <= right.val }
198+
Float { return left.val <= right.val }
199+
i64 { return left.val <= right }
200+
f64 { return left.val <= right }
201+
else { e.error('invalid operands to <=: Int and ${right.type_name()}') }
202+
}
203+
}
204+
Uint {
205+
match right {
206+
Int { return left.val <= right.val }
207+
Uint { return left.val <= right.val }
208+
Float { return left.val <= right.val }
209+
i64 { return left.val <= right }
210+
f64 { return left.val <= right }
211+
else { e.error('invalid operands to <=: Uint and ${right.type_name()}') }
212+
}
213+
}
214+
Float {
215+
match right {
216+
Int { return left.val <= right.val }
217+
Uint { return left.val <= right.val }
218+
Float { return left.val <= right.val }
219+
i64 { return left.val <= right }
220+
f64 { return left.val <= right }
221+
else { e.error('invalid operands to <=: Float and ${right.type_name()}') }
222+
}
223+
}
224+
i64 {
225+
match right {
226+
Int { return left <= right.val }
227+
Uint { return left <= right.val }
228+
Float { return left <= right.val }
229+
i64 { return left <= right }
230+
f64 { return left <= right }
231+
else { e.error('invalid operands to <=: int literal and ${right.type_name()}') }
232+
}
233+
}
234+
f64 {
235+
match right {
236+
Int { return left <= right.val }
237+
Uint { return left <= right.val }
238+
Float { return left <= right.val }
239+
i64 { return left <= right }
240+
f64 { return left <= right }
241+
else { e.error('invalid operands to <=: float literal and ${right.type_name()}') }
242+
}
243+
}
244+
else {
245+
e.error('invalid operands to <=: ${left.type_name()} and ${right.type_name()}')
246+
}
247+
}
248+
}
123249
.eq {
124250
match left {
125251
Int {

‎vlib/v/eval/stmt.v‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,16 @@ import v.ast
44
import v.token
55

66
pub fn (mut e Eval) stmts(stmts []ast.Stmt) {
7+
if e.executed_return_stmt {
8+
return
9+
}
710
e.open_scope()
811
for stmt in stmts {
9-
e.stmt(stmt)
10-
if e.returning {
12+
if !e.executed_return_stmt {
13+
e.stmt(stmt)
14+
}
15+
if stmt is ast.Return {
16+
e.executed_return_stmt = true
1117
break
1218
}
1319
}

‎vlib/v/eval/tests/comptime_if_test.v‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,24 @@ fn test_comptime_if_without_func() {
4747
dump(ret)
4848
assert ret == []
4949
}
50+
51+
fn test_comptime_if_infix() {
52+
mut e := eval.create()
53+
54+
ret := e.run('const a =
55+
\$if amd64 || aarch64 || arm64 || rv64 { "64bit" }
56+
\$else \$if i386 || arm32 || rv32 { "32bit" }
57+
\$else \$if s390x { "s390x" }
58+
\$else \$if ppc64le { "ppc64le" }
59+
\$else \$if loongarch64 { "loongarch64" }
60+
\$else { "unknown" }
61+
62+
const b = 1.5
63+
64+
fn display() (string,f64) { println(a) println(b) return a,b } display()')!
65+
66+
dump(ret)
67+
assert ret[0].string().len != 0
68+
assert ret[0].string() != 'unknown'
69+
assert ret[1].float_val() == 1.5
70+
}

‎vlib/v/eval/tests/if_test.v‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,46 @@ fn test_if_return() {
2929
dump(ret1)
3030
assert ret1[0].int_val() == 666
3131
}
32+
33+
fn test_if_infix_return_early() {
34+
mut e := eval.create()
35+
36+
ret := e.run('
37+
fn display(a int, b int) int {
38+
mut k := false
39+
if !k {
40+
k = !k
41+
}
42+
println(k)
43+
if a == 100 && b == 100 {
44+
return 100
45+
} else if a == 100 && b != 100 {
46+
return 101
47+
} else if a == 100 && b > 100 {
48+
return 102
49+
} else if a == 100 && b < 100 {
50+
return 103
51+
} else if a == 100 && b >= 100 {
52+
return 104
53+
} else if a == 100 && b <= 100 {
54+
return 105
55+
} else if a == 100 || b == 100 {
56+
return 106
57+
} else if a == 100 || b != 100 {
58+
return 107
59+
} else if a == 100 || b > 100 {
60+
return 108
61+
} else if a == 100 || b < 100 {
62+
return 109
63+
} else if a == 100 || b >= 100 {
64+
return 110
65+
} else if a == 100 || b <= 100 {
66+
return 111
67+
}
68+
return 7171
69+
}
70+
display(200, 101)')!
71+
72+
dump(ret)
73+
assert ret[0].int_val() == 107
74+
}

0 commit comments

Comments
 (0)