Skip to content

Commit d3f2b18

Browse files
committed
feat: remove eval function and update related tests; enhance pattern matching and runtime value operations
1 parent ff38aab commit d3f2b18

10 files changed

Lines changed: 258 additions & 79 deletions

File tree

‎interpreter/core/builtin.mbt‎

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ let core_stubs : Map[String, String] = {
55
"println_mono": "%println",
66
"println": "%println_mono",
77
"typeof": "%typeof",
8-
"eval": "%eval",
98
"require": "%require",
109
"panic": "%panic",
1110
"abort": "%abort",
@@ -20,7 +19,6 @@ let builtin_embedded_code : Map[String, RuntimeFunction] = {
2019
"%abort": abort_fn,
2120
"%panic": panic_fn,
2221
"%typeof": typeof_fn,
23-
"%eval": eval_fn,
2422
"%require": require_fn,
2523
"%println_mono": println_mono_fn,
2624
"%ignore": ignore_fn,
@@ -251,20 +249,6 @@ let typeof_fn : RuntimeFunction = ctx => {
251249
}
252250
}
253251

254-
///|
255-
let eval_fn : RuntimeFunction = ctx => {
256-
match ctx.args {
257-
[{ val: String(code), .. }] => {
258-
let expr = parse_code_to_expr(code)
259-
match expr {
260-
Ok(expr) => ctx.context.visit(expr)
261-
Err(error) => raise Raise(String(error))
262-
}
263-
}
264-
_ => Unit
265-
}
266-
}
267-
268252
///|
269253
let require_fn : RuntimeFunction = ctx => {
270254
match ctx.args {

‎interpreter/core/functions.mbt‎

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,17 +163,21 @@ fn ClosureInterpreter::bind_runtime_parameters(
163163
_ => break
164164
}
165165
(@list.More(param, tail=rest_params), @list.More(arg, tail=rest_args)) => {
166-
let value = arg.val
167166
match param {
168167
// 位置参数:直接绑定参数值
169-
Positional(binder={ name, .. }, ..)
168+
Positional(binder={ name, .. }, ty~)
170169
// 标签参数:绑定带标签的参数值
171-
| Labelled(binder={ name, .. }, ..)
170+
| Labelled(binder={ name, .. }, ty~)
172171
// 问号可选参数:绑定参数值
173-
| QuestionOptional(binder={ name, .. }, ..)
172+
| QuestionOptional(binder={ name, .. }, ty~)
174173
// 可选参数:当有参数提供时绑定参数值
175-
| Optional(binder={ name, .. }, ..) =>
174+
| Optional(binder={ name, .. }, ty~, ..) => {
175+
let value = match ty {
176+
Some(ty) => arg.val.overload_literal(extract_type_name(ty))
177+
None => arg.val
178+
}
176179
self.current_pkg.env.set(name, value)
180+
}
177181
// 丢弃位置参数:不绑定到任何变量
178182
DiscardPositional(..) => ()
179183
}

‎interpreter/core/interpreter.mbt‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ pub(all) struct ClosureInterpreter {
1515
///|
1616
pub fn ClosureInterpreter::new() -> ClosureInterpreter {
1717
let main = RuntimePackage::new("main")
18+
main.deps.set("builtin", moonbitlang_core_builtin_module)
19+
main.deps.set("moonbitlang/core/builtin", moonbitlang_core_builtin_module)
1820
main.deps.set("fs", fs_package)
1921
let self = {
2022
extern_fns: {},
@@ -24,6 +26,7 @@ pub fn ClosureInterpreter::new() -> ClosureInterpreter {
2426
current_pkg: main,
2527
call_stack: [],
2628
}
29+
self.load_package(moonbitlang_core_builtin_module)
2730
self.load_package(main)
2831
self
2932
}

‎interpreter/core/method_execution.mbt‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,18 @@ fn ClosureInterpreter::call_by_name(
8888
.to_array(),
8989
)
9090
self.with_ident(long_ident, (pkg, name) => {
91-
let name = pkg.find_stub(name)
9291
match self.lookup_function(pkg, name) {
9392
FunctionLookupResult::DirectFunction(func) =>
9493
self.execute_embedded_function(func, evaluated_args)
9594
FunctionLookupResult::NotFound =>
96-
self.error(
97-
"execute_function_by_name method @\{pkg.name}.\{name} not found",
98-
)
95+
match self.lookup_function(pkg, pkg.find_stub(name)) {
96+
FunctionLookupResult::DirectFunction(func) =>
97+
self.execute_embedded_function(func, evaluated_args)
98+
FunctionLookupResult::NotFound =>
99+
self.error(
100+
"execute_function_by_name method @\{pkg.name}.\{name} not found",
101+
)
102+
}
99103
}
100104
})
101105
}

‎interpreter/core/pattern_matching.mbt‎

Lines changed: 144 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,83 @@ pub fn ClosureInterpreter::match_case(
191191
value : RuntimeValue,
192192
pattern : @syntax.Pattern,
193193
) -> Bool {
194+
fn match_array_pattern_list(
195+
patterns : @list.List[@syntax.ArrayPattern],
196+
values : Array[RuntimeValue],
197+
start : Int,
198+
) -> Bool {
199+
let mut index = start
200+
for state = patterns {
201+
match state {
202+
@list.More(array_pat, tail=pat_tail) => {
203+
if index >= values.length() {
204+
return false
205+
}
206+
match array_pat {
207+
@syntax.ArrayPattern::Pattern(pat) =>
208+
if !self.match_case(values[index], pat) {
209+
return false
210+
}
211+
_ => return false
212+
}
213+
index += 1
214+
continue pat_tail
215+
}
216+
@list.Empty => break
217+
}
218+
}
219+
true
220+
}
221+
222+
fn map_pattern_key(key : @syntax.Constant) -> RuntimeValue? {
223+
match key {
224+
String(str) => Some(String(str))
225+
Int(str) =>
226+
Some(Int(@string.parse_int(str), raw=None)) catch {
227+
_ => None
228+
}
229+
_ => None
230+
}
231+
}
232+
233+
fn json_pattern_key(key : @syntax.Constant) -> String? {
234+
match key {
235+
String(str) => Some(str)
236+
_ => None
237+
}
238+
}
239+
240+
fn match_json_constructor(
241+
json : Json,
242+
constr_name : String,
243+
pattern_args : @list.List[@syntax.ConstrPatArg]?,
244+
) -> Bool {
245+
fn match_unary(value : RuntimeValue) -> Bool {
246+
match pattern_args {
247+
Some(@list.More(arg, tail=@list.Empty)) =>
248+
self.match_case(value, arg.pat)
249+
_ => false
250+
}
251+
}
252+
match (json, constr_name, pattern_args) {
253+
(Null, "Null", None) => true
254+
(True, "True", None) => true
255+
(False, "False", None) => true
256+
(String(str), "String", _) => match_unary(String(str))
257+
(Number(num, ..), "Number", _) => match_unary(Double(num))
258+
(Array(arr), "Array", _) =>
259+
match_unary(Array(arr.map(item => Json(item))))
260+
(Object(obj), "Object", _) => {
261+
let map : Map[RuntimeValue, RuntimeValue] = {}
262+
for key, item in obj {
263+
map.set(String(key), Json(item))
264+
}
265+
match_unary(Map(map))
266+
}
267+
_ => false
268+
}
269+
}
270+
194271
match pattern {
195272
// 变量模式匹配(总是匹配,并绑定变量)
196273
Var({ name, .. }) => {
@@ -275,26 +352,38 @@ pub fn ClosureInterpreter::match_case(
275352
if values.length() != patterns.length() {
276353
return false
277354
}
278-
let mut index = 0
279-
for state = patterns {
280-
match state {
281-
@list.More(array_pat, tail=pat_tail) => {
282-
match array_pat {
283-
@syntax.ArrayPattern::Pattern(pat) =>
284-
if !self.match_case(values[index], pat) {
285-
return false
286-
}
287-
_ => return false // 其他数组模式暂不支持
288-
}
289-
index = index + 1
290-
continue pat_tail
291-
}
292-
@list.Empty => break
293-
}
355+
match_array_pattern_list(patterns, values, 0)
356+
}
357+
@syntax.ArrayPatterns::Open(left, right, binder) => {
358+
let left_len = left.length()
359+
let right_len = right.length()
360+
if values.length() < left_len + right_len {
361+
return false
362+
}
363+
if !match_array_pattern_list(left, values, 0) {
364+
return false
365+
}
366+
if !match_array_pattern_list(
367+
right,
368+
values,
369+
values.length() - right_len,
370+
) {
371+
return false
372+
}
373+
let rest_view = values[left_len:values.length() - right_len]
374+
let rest = Array::new(capacity=rest_view.length())
375+
for item in rest_view {
376+
rest.push(item)
377+
}
378+
match binder {
379+
@syntax.DotDotBinder::Binder(binder) =>
380+
self.current_pkg.env.set(binder.name, Array(rest))
381+
@syntax.DotDotBinder::BinderAs(binder) =>
382+
self.current_pkg.env.set(binder.name, Array(rest))
383+
_ => ()
294384
}
295385
true
296386
}
297-
_ => false // 其他数组模式暂不支持
298387
}
299388
_ => false
300389
}
@@ -320,6 +409,42 @@ pub fn ClosureInterpreter::match_case(
320409
}
321410
_ => false
322411
}
412+
Map(elems~, ..) =>
413+
match value {
414+
Map(values) => {
415+
for elem in elems {
416+
match map_pattern_key(elem.key) {
417+
Some(key) =>
418+
match values.get(key) {
419+
Some(item) =>
420+
if !self.match_case(item, elem.pat) {
421+
return false
422+
}
423+
None => return false
424+
}
425+
None => return false
426+
}
427+
}
428+
true
429+
}
430+
Json(Object(values)) => {
431+
for elem in elems {
432+
match json_pattern_key(elem.key) {
433+
Some(key) =>
434+
match values.get(key) {
435+
Some(item) =>
436+
if !self.match_case(Json(item), elem.pat) {
437+
return false
438+
}
439+
None => return false
440+
}
441+
None => return false
442+
}
443+
}
444+
true
445+
}
446+
_ => false
447+
}
323448

324449
// Range模式匹配
325450
Range(lhs~, rhs~, kind~, ..) =>
@@ -328,6 +453,8 @@ pub fn ClosureInterpreter::match_case(
328453
// Constructor模式匹配
329454
Constr(constr~, args=pattern_args, ..) =>
330455
match value {
456+
Json(json) =>
457+
match_json_constructor(json, constr.name.name, pattern_args)
331458
Constructor({ val: { name, fields }, ty }) =>
332459
if name == constr.name.name &&
333460
self.constructor_pattern_matches_type(ty, constr) {

‎interpreter/core/runtime_value.mbt‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -938,9 +938,13 @@ pub fn runtime_value_infix(
938938
// Char 运算
939939
(Char(left), Char(right)) =>
940940
match op {
941-
"+" => String(left.to_string() + right.to_string())
941+
"+" => String([left, right])
942942
"==" => Bool(left == right)
943943
"!=" => Bool(left != right)
944+
"<" => Bool(left < right)
945+
">" => Bool(left > right)
946+
"<=" => Bool(left <= right)
947+
">=" => Bool(left >= right)
944948
_ => Unit
945949
}
946950
// Bytes 运算
@@ -961,6 +965,7 @@ pub fn runtime_value_infix(
961965
}
962966
(Array(left), Array(right)) =>
963967
match op {
968+
"+" => Array(left + right)
964969
"==" => Bool(left == right)
965970
"!=" => Bool(left != right)
966971
_ => Unit

‎moon.mod.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
"version": "0.9.2",
44
"deps": {
55
"moonbitlang/parser": "0.3.0",
6-
"moonbitlang/x": "0.4.43"
6+
"moonbitlang/x": "0.4.43",
7+
"moonbitlang/async": "0.19.0"
78
},
89
"readme": "README.md",
910
"repository": "https://github.com/oboard/eval",

‎test/eval.mbt‎

Lines changed: 6 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,14 @@
11
///|
2-
test "eval" {
2+
test "eval_can_be_user_defined" {
33
let vm = MoonBitVM::new()
4-
let result = vm.eval("eval(\"1 + 2\")")
5-
inspect(result, content="3")
6-
}
7-
8-
///|
9-
test "eval eval" {
10-
let vm = MoonBitVM::new()
11-
let result = vm.eval("eval(\"eval(\\\"1 + 2\\\")\")")
12-
inspect(result, content="3")
13-
}
14-
15-
///|
16-
test "typeof eval" {
17-
let vm = MoonBitVM::new()
18-
inspect(
19-
vm.eval(
20-
(
21-
#|typeof(eval("(1+2).to_string()"))
22-
),
23-
),
24-
content="@moonbitlang/core/string.String",
25-
)
26-
inspect(
27-
vm.eval(
28-
(
29-
#|typeof(eval("1+2"))
30-
),
31-
),
32-
content="@moonbitlang/core/int.Int",
33-
)
34-
inspect(
4+
ignore(
355
vm.eval(
366
(
37-
#|eval("1+2") is 3
7+
#|fn eval(value : Int) -> Int {
8+
#| value + 1
9+
#|}
3810
),
3911
),
40-
content="true",
4112
)
13+
inspect(vm.eval("eval(2)"), content="3")
4214
}

0 commit comments

Comments
 (0)