Skip to content

Commit 42427da

Browse files
committed
refactor: string handling and improve diagnostics
- Updated string handling functions to utilize the built-in StringBuilder for better performance and consistency. - Enhanced the RuntimeLocation enum with a Debug representation. - Modified various string-related functions to improve code clarity and maintainability. - Changed diagnostics handling to use lexer reports instead of parser reports. - Updated package dependencies to newer versions for improved functionality and stability. - Refactored test cases to align with new function signatures and improve readability. - Added output and to_string methods for EvalResult, TestFailure, and TestResult for better logging and debugging.
1 parent 2c4c9ae commit 42427da

58 files changed

Lines changed: 27698 additions & 20051 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎async/pkg.generated.mbti‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,3 @@ package "oboard/eval/async"
1010
// Type aliases
1111

1212
// Traits
13-

‎benchmark_test.mbt‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
// 表达式求值基准测试
66
test "benchmark_arithmetic_expressions" (b : @bench.T) {
7-
let vm = MoonBitVM::new(log=false)
7+
let vm = @eval.MoonBitVM::new(log=false)
88
let code = "1 + 2 * 3 - 4 / 2 + (5 * 6) - 7"
99
b.bench(fn() { b.keep(vm.eval(code)) })
1010
}
@@ -16,14 +16,14 @@ test "native_benchmark_arithmetic_expressions" (b : @bench.T) {
1616

1717
///|
1818
test "benchmark_compiled_arithmetic_expressions" (b : @bench.T) {
19-
let vm = MoonBitVM::new(log=false)
19+
let vm = @eval.MoonBitVM::new(log=false)
2020
let compiled = vm.compile("1 + 2 * 3 - 4 / 2 + (5 * 6) - 7")
2121
b.bench(fn() { b.keep(compiled.run(vm)) })
2222
}
2323

2424
///|
2525
test "benchmark_compiled_parameters" (b : @bench.T) {
26-
let vm = MoonBitVM::new(log=false)
26+
let vm = @eval.MoonBitVM::new(log=false)
2727
let compiled = vm.compile("a + b * c - d / e + f * g - h", params=[
2828
"a", "b", "c", "d", "e", "f", "g", "h",
2929
])
@@ -34,7 +34,7 @@ test "benchmark_compiled_parameters" (b : @bench.T) {
3434

3535
///|
3636
test "benchmark_variable_access" (b : @bench.T) {
37-
let vm = MoonBitVM::new(log=false)
37+
let vm = @eval.MoonBitVM::new(log=false)
3838

3939
// 设置变量
4040
vm.run("let x = 42; let y = 100; let z = x + y")
@@ -45,7 +45,7 @@ test "benchmark_variable_access" (b : @bench.T) {
4545

4646
///|
4747
test "benchmark_function_calls" (b : @bench.T) {
48-
let vm = MoonBitVM::new(log=false)
48+
let vm = @eval.MoonBitVM::new(log=false)
4949
let code = "fn add(x, y) { x + y }; fn mul(x, y) { x * y }; fn complex(a, b, c) { add(mul(a, b), c) }; complex(10, 20, 30)"
5050
b.bench(fn() { b.keep(vm.eval(code)) })
5151
}
@@ -54,7 +54,7 @@ test "benchmark_function_calls" (b : @bench.T) {
5454

5555
///|
5656
test "benchmark_array_operations" (b : @bench.T) {
57-
let vm = MoonBitVM::new(log=false)
57+
let vm = @eval.MoonBitVM::new(log=false)
5858
let code = "let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let sum = arr[0] + arr[1] + arr[2] + arr[3] + arr[4]; sum"
5959
b.bench(fn() { b.keep(vm.eval(code)) })
6060
}
@@ -63,7 +63,7 @@ test "benchmark_array_operations" (b : @bench.T) {
6363

6464
///|
6565
test "benchmark_recursive_functions" (b : @bench.T) {
66-
let vm = MoonBitVM::new(log=false)
66+
let vm = @eval.MoonBitVM::new(log=false)
6767
let code = "fn fibonacci(n) { if n <= 1 { n } else { fibonacci(n - 1) + fibonacci(n - 2) } }; fibonacci(10)"
6868
b.bench(fn() { b.keep(vm.eval(code)) })
6969
}
@@ -72,7 +72,7 @@ test "benchmark_recursive_functions" (b : @bench.T) {
7272

7373
///|
7474
test "benchmark_tail_recursive_fibonacci" (b : @bench.T) {
75-
let vm = MoonBitVM::new(log=false)
75+
let vm = @eval.MoonBitVM::new(log=false)
7676
let code = "fn fib_tail(n, a, b) { if n == 0 { a } else { fib_tail(n - 1, b, a + b) } }; fn fibonacci_fast(n) { fib_tail(n, 0, 1) }; fibonacci_fast(10)"
7777
b.bench(fn() { b.keep(vm.eval(code)) })
7878
}
@@ -81,7 +81,7 @@ test "benchmark_tail_recursive_fibonacci" (b : @bench.T) {
8181

8282
///|
8383
test "benchmark_iterative_fibonacci" (b : @bench.T) {
84-
let vm = MoonBitVM::new(log=false)
84+
let vm = @eval.MoonBitVM::new(log=false)
8585
let code = "fn fibonacci_iter(n) { let mut a = 0; let mut b = 1; let mut i = 0; while i < n { let temp = a + b; a = b; b = temp; i = i + 1 }; a }; fibonacci_iter(10)"
8686
b.bench(fn() { b.keep(vm.eval(code)) })
8787
}
@@ -90,7 +90,7 @@ test "benchmark_iterative_fibonacci" (b : @bench.T) {
9090

9191
///|
9292
test "benchmark_complex_expressions" (b : @bench.T) {
93-
let vm = MoonBitVM::new(log=false)
93+
let vm = @eval.MoonBitVM::new(log=false)
9494
let code = "let a = 10; let b = 20; let c = 30; (a + b) * c - (a * b) + (c / 2) - (a - b)"
9595
b.bench(fn() { b.keep(vm.eval(code)) })
9696
}

‎example/moon.pkg‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,4 @@ import {
22
"oboard/eval",
33
}
44

5-
options(
6-
"is-main": true,
7-
)
5+
pkgtype(kind: "executable")

‎example/pkg.generated.mbti‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,3 @@ package "oboard/eval/example"
1010
// Type aliases
1111

1212
// Traits
13-

‎export.mbt‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ pub fn test_result_to_string(result : TestResult) -> String {
6262
///|
6363
pub fn code_to_ast(code : String) -> String {
6464
match @core.parse_eval_code(code) {
65-
Ok(EvalExpr(expr)) => expr.to_json().stringify()
66-
Ok(EvalTop(impls, ..)) => impls.to_json().stringify()
65+
Ok(EvalExpr(expr)) => @json.to_json(expr).stringify()
66+
Ok(EvalTop(impls, ..)) => @json.to_json(impls).stringify()
6767
Err(msg) => msg
6868
}
6969
}

‎generate_core_modules.py‎

Lines changed: 77 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,48 +3,106 @@
33
Generate embedded core modules for moonbit-eval interpreter.
44
This script reads all modules from moonbitlang/core and generates
55
RuntimePackage definitions in the format expected by core_modules.mbt.
6+
It honors the `options.targets` directive in each package's moon.pkg
7+
to include only files relevant for the js target.
68
"""
79

810
import os
11+
import re
912
from pathlib import Path
10-
from typing import Dict, List
13+
from typing import Dict, List, Optional, Set, Tuple
1114

1215
# Core library path
1316
CORE_PATH = "/Users/oboard/.moon/lib/core"
1417
OUTPUT_FILE = "interpreter/core/core_modules.mbt"
1518

16-
# Removed extract_all_items function - no longer needed with new format
19+
# Target we are building for
20+
BUILD_TARGET = "js"
1721

18-
def read_module_info(module_dir: Path) -> Dict:
22+
def parse_targets(moon_pkg_content: str) -> Dict[str, List[str]]:
23+
"""Parse options(targets: { ... }) from moon.pkg content.
24+
25+
Returns a dict mapping filename -> list of target strings.
26+
Files not listed in targets are included for all targets.
1927
"""
20-
Read module information from a directory.
21-
Returns dict with module name, dependencies, and concatenated code content.
28+
targets = {}
29+
# Match options(targets: { ... }) block
30+
m = re.search(r'targets\s*:\s*\{([^}]*)\}', moon_pkg_content, re.DOTALL)
31+
if not m:
32+
return targets
33+
34+
block = m.group(1)
35+
# Parse each entry: "filename": [ "target1", "target2" ]
36+
for entry_m in re.finditer(r'"([^"]+)"\s*:\s*\[([^\]]*)\]', block):
37+
filename = entry_m.group(1)
38+
targets_str = entry_m.group(2)
39+
target_list = [t.strip().strip('"') for t in targets_str.split(',') if t.strip().strip('"')]
40+
targets[filename] = target_list
41+
42+
return targets
43+
44+
def should_include_file(filename: str, targets: Dict[str, List[str]], build_target: str) -> bool:
45+
"""Determine if a file should be included for the given build target.
46+
47+
Rules:
48+
- If file is not in targets dict, include for all targets.
49+
- If the target list starts with "not", include for targets NOT in the list.
50+
- Otherwise, include only for targets IN the list.
2251
"""
52+
if filename not in targets:
53+
return True
54+
55+
target_list = targets[filename]
56+
if not target_list:
57+
return True
58+
59+
if target_list[0] == "not":
60+
# Exclude for listed targets
61+
return build_target not in target_list[1:]
62+
else:
63+
# Include only for listed targets
64+
return build_target in target_list
65+
66+
def read_module_info(module_dir: Path) -> Optional[Dict]:
67+
"""Read module information from a directory."""
2368
pkg = "moonbitlang/core/" + module_dir.relative_to(CORE_PATH).as_posix()
2469
alias = module_dir.relative_to(CORE_PATH).as_posix()
2570
module_name = pkg.replace('/', '_')
2671

27-
# Keep embedded package deps empty to avoid introducing definition cycles.
28-
# The generated file is used as a flat registry of embedded packages.
2972
dependencies = []
3073

74+
# Read moon.pkg to get targets
75+
moon_pkg_path = module_dir / "moon.pkg"
76+
file_targets = {}
77+
if moon_pkg_path.exists():
78+
try:
79+
with open(moon_pkg_path, 'r', encoding='utf-8') as f:
80+
pkg_content = f.read()
81+
file_targets = parse_targets(pkg_content)
82+
except (UnicodeDecodeError, FileNotFoundError):
83+
pass
84+
3185
# Find all .mbt files (excluding test files)
3286
mbt_files = [f for f in module_dir.glob("*.mbt")
3387
if not f.name.endswith('_test.mbt') and not f.name.endswith('_wbtest.mbt')]
3488

35-
# Collect file contents with their names
89+
# Collect file contents with their names, filtering by target
3690
file_contents = {}
3791

38-
for mbt_file in sorted(mbt_files): # Sort for consistent ordering
92+
for mbt_file in sorted(mbt_files):
93+
if not should_include_file(mbt_file.name, file_targets, BUILD_TARGET):
94+
continue
3995
try:
4096
with open(mbt_file, 'r', encoding='utf-8') as f:
4197
content = f.read().strip()
42-
if content: # Only add non-empty content
98+
if content:
4399
file_contents[mbt_file.name] = content
44100
except (UnicodeDecodeError, FileNotFoundError):
45101
continue
46102

47-
# Join all content with double newlines for backward compatibility
103+
if not file_contents:
104+
return None
105+
48106
concatenated_code = '\n\n'.join(file_contents.values())
49107

50108
return {
@@ -56,19 +114,14 @@ def read_module_info(module_dir: Path) -> Dict:
56114
'files': file_contents
57115
}
58116

59-
# Removed has_non_self_parameters function - no longer needed with new format
60-
61117
def generate_module_code(module_info: Dict) -> str:
62-
"""
63-
Generate RuntimePackage code for a single module.
64-
"""
118+
"""Generate RuntimePackage code for a single module."""
65119
pkg = module_info['pkg']
66120
module_name = module_info['name']
67-
code = module_info['code']
68121
dependencies = module_info['dependencies']
69122
files = module_info['files']
70123

71-
if not code.strip():
124+
if not files:
72125
return ""
73126

74127
# Generate dependencies map
@@ -85,22 +138,18 @@ def generate_module_code(module_info: Dict) -> str:
85138
# Generate files map
86139
files_map_entries = []
87140
for filename, content in files.items():
88-
# Format the code with #| prefix for each line, filtering out comments and empty lines
89141
code_lines = content.split('\n')
90142
formatted_code_lines = []
91143
for line in code_lines:
92-
# Skip comment lines and empty lines to reduce file size
93144
stripped_line = line.strip()
94-
if not stripped_line or stripped_line.startswith('//') or stripped_line.startswith('///') or stripped_line.startswith('///'):
145+
if not stripped_line or stripped_line.startswith('//') or stripped_line.startswith('///'):
95146
continue
96-
# Escape quotes and backslashes for the string literal
97147
formatted_code_lines.append(f' #|{line}')
98148

99149
if formatted_code_lines:
100150
formatted_content = '\n'.join(formatted_code_lines)
101151
files_map_entries.append(f' "{filename}": (\n{formatted_content}\n )')
102152
else:
103-
# For empty files, generate empty string
104153
files_map_entries.append(f' "{filename}": ""')
105154

106155
files_map_str = ',\n'.join(files_map_entries)
@@ -117,9 +166,7 @@ def generate_module_code(module_info: Dict) -> str:
117166
return module_code
118167

119168
def generate_core_modules_map(modules: List[dict]) -> str:
120-
"""
121-
Generate the core_modules map declaration.
122-
"""
169+
"""Generate the core_modules map declaration."""
123170
entries = []
124171
for module in modules:
125172
entries.append(f'"{module["alias"]}": {module["name"]}_module')
@@ -130,19 +177,17 @@ def generate_core_modules_map(modules: List[dict]) -> str:
130177
let core_modules : Map[String, RuntimePackage] = {{ {map_content} }}'''
131178

132179
def main():
133-
"""
134-
Main function to generate all core modules.
135-
"""
180+
"""Main function to generate all core modules."""
136181
core_path = Path(CORE_PATH)
137182

138183
if not core_path.exists():
139184
print(f"Error: Core path {CORE_PATH} does not exist")
140185
return
186+
141187
# Get all module directories recursively
142188
module_dirs = []
143189
for root, dirs, _ in os.walk(core_path):
144190
root_path = Path(root)
145-
# Skip hidden directories and build artifacts.
146191
dirs[:] = [
147192
d
148193
for d in dirs
@@ -155,21 +200,20 @@ def main():
155200
generated_modules = []
156201
module_codes = []
157202

158-
# Process each module
159203
for module_dir in sorted(module_dirs):
160204
print(f"Processing module: {module_dir.name}")
161205

162206
module_info = read_module_info(module_dir)
163207

164-
if module_info['code'].strip():
208+
if module_info and module_info['code'].strip():
165209
module_code = generate_module_code(module_info)
166210
if module_code:
167211
module_codes.append(module_code)
168212
generated_modules.append(module_info)
169213
code_lines = len([line for line in module_info['code'].split('\n') if line.strip()])
170214
print(f" Generated module with {code_lines} lines of code")
171215
else:
172-
print(f" No code content found")
216+
print(f" No code content found (filtered by target)")
173217

174218
# Generate the complete file content
175219
header = '''///|
@@ -185,17 +229,14 @@ def main():
185229
}
186230
}'''
187231

188-
# Generate core_modules map
189232
core_modules_map = generate_core_modules_map(generated_modules)
190233

191-
# Combine all parts
192234
full_content = "\n\n".join([
193235
header,
194236
core_modules_map,
195237
dummy_loc
196238
] + module_codes)
197239

198-
# Write to output file
199240
output_path = Path(OUTPUT_FILE)
200241
with open(output_path, 'w', encoding='utf-8') as f:
201242
f.write(full_content)

0 commit comments

Comments
 (0)