///|
test "basic expression printing" {
let expr = "let x = 1 + 2"
let result = parse_impl(expr)
let printed = to_string_impl(result)
inspect(printed, content="let x = 1 + 2")
// Test with simple expression
let expr2 = "1 + 2"
let result2 = parse_impl(expr2)
let printed2 = to_string_impl(result2)
inspect(printed2, content="_")
}
///|
test "constant expressions" {
let result1 = parse_impl("let x = 42")
inspect(to_string_impl(result1), content="let x = 42")
let result2 = parse_impl("let y = true")
inspect(to_string_impl(result2), content="let y = true")
let result3 = parse_impl("let z = \"hello\"")
inspect(
to_string_impl(result3),
content=(
#|let z = "hello"
),
)
}
///|
test "function definitions" {
let func_def = "fn add(x : Int, y : Int) -> Int { x + y }"
let result = parse_impl(func_def)
let printed = to_string_impl(result)
inspect(printed, content="fn add(x : Int, y : Int) -> Int { x + y }")
}
///|
test "comprehensive printer functionality demo" {
// Test various language constructs
let examples = [
"let x = 42", "pub const PI = 3.14", "let result = x + y * z", "fn factorial(n : Int) -> Int { if n <= 1 { 1 } else { n * factorial(n - 1) } }",
"struct Point { x : Int, y : Int }", "test \"addition\" { assert_eq(1 + 1, 2) }",
]
for example in examples {
let result = parse_impl(example)
let printed = to_string_impl(result)
// Just verify they don't crash - actual content verified in other tests
ignore(printed)
}
}
///|
test "type definitions" {
let type_def = "struct Point { x : Int, y : Int }"
let result = parse_impl(type_def)
let printed = to_string_impl(result)
inspect(printed, content="struct Point { x : Int; y : Int; }")
}
///|
test "visibility modifiers" {
let pub_let = "pub let x = 42"
let result = parse_impl(pub_let)
let printed = to_string_impl(result)
inspect(printed, content="pub let x = 42")
}
///|
test "test definitions" {
let test_def = "test \"sample test\" { assert_eq(1 + 1, 2) }"
let result = parse_impl(test_def)
let printed = to_string_impl(result)
inspect(printed, content="test \"sample test\" { assert_eq(1 + 1, 2) }")
}
///|
test {
let s = "let expr : Int = { let x = 1; let y = x + 3; y * 2 }"
let result = parse_impl(s)
let printed = to_string_impl(result)
inspect(
printed,
content="let expr : Int = { let x = 1; let y = x + 3; y * 2 }",
)
}
///|
///|
/// Get all MoonBit packages from a directory
/// Filters out files and hidden directories (starting with ".")
fn get_moonbit_package(dir_path : String) -> Array[String] raise {
let packages = try! @fs.read_dir(dir_path)
let packages = packages.filter(fn(p) { not(@fs.is_file(dir_path + "/" + p)) })
packages.filter(fn(p) { not(p.has_prefix(".")) })
}
///|
/// Get all MoonBit source files from a package directory
/// Returns files with .mbt extension
fn get_moonbit_source_file(package_path : String) -> Array[String] {
let files = try! @fs.read_dir(package_path)
files.filter(fn(f) { f.has_suffix(".mbt") })
}
///|
fn prop_print_identity(path : String, progress~ : String) -> Unit raise {
let s = try! @fs.read_file_to_string(path)
let impls = @parser.parse_string(s).0
for impl_ in impls {
let printed = to_string_impl(impl_)
let reparsed = parse_impl(printed)
let reprinted = to_string_impl(reparsed)
let loc = impl_.loc()
assert_eq(
printed,
reprinted,
msg=(
$|progress: \{progress}
$|
$|printed: `\{printed} `
$|
$|reprinted: `\{reprinted} `
$|
$| \{path}:\{loc.start.lnum}:\{loc.start.column()}-\{loc.end.lnum}:\{loc.end.column()}
),
)
}
}
///|
fn get_all_test_path() -> Array[String] {
let path = []
let module_path = "./examples/core"
let packages = try! get_moonbit_package(module_path)
for pkg in packages {
let package_path = module_path + "/" + pkg
let source_files = get_moonbit_source_file(package_path)
for file in source_files {
path.push(package_path + "/" + file)
}
}
path
}
///|
test "package references printing" {
// Test type references with package prefix
let type_ref = "let x : @list.List[Int] = @list.empty()"
let result1 = parse_impl(type_ref)
let printed1 = to_string_impl(result1)
inspect(printed1, content="let x : @list.List[Int] = @list.empty()")
// Test method references with package prefix
let method_ref = "@json.inspect(x, content=\"test\")"
let result2 = parse_impl(method_ref)
let printed2 = to_string_impl(result2)
inspect(printed2, content="_")
// Test trait references in type constraints
let trait_ref = "fn[T : @json.ToJson] test(x : T) -> Unit { ... }"
let result3 = parse_impl(trait_ref)
let printed3 = to_string_impl(result3)
inspect(printed3, content="fn[T : @json.ToJson] () { _ }")
}
///|
test {
let s = "test { inspect(0N.bit_length(),content=\"0\") }"
let result = parse_impl(s)
inspect(
to_string_impl(result),
content=(
#|test { inspect(0N.bit_length(), content="0") }
),
)
}
///|
test {
let all_path = get_all_test_path()
let total = all_path.length()
let mut idx = 0
for path in all_path {
prop_print_identity(path, progress="\{idx}/\{total}")
idx = idx + 1
}
}
///|
test {
let s = "let odd_even : ((Int) -> Bool, (Int) -> Bool) = { letrec is_odd = fn(n : Int) -> Bool { if n == 0 { false } else { is_even(n - 1) } } and is_even = fn(n : Int) -> Bool { if n == 0 { true } else { is_odd(n - 1) } } ; (is_odd,is_even) }"
let r = parse_impl(s)
inspect(
to_string_impl(r),
content="let odd_even : ((Int) -> Bool, (Int) -> Bool) = { letrec is_odd = fn(n : Int) -> Bool { if n == 0 { false } else { is_even(n - 1) } } and is_even = fn(n : Int) -> Bool { if n == 0 { true } else { is_odd(n - 1) } }; (is_odd, is_even) }",
)
}