richer formatting

This commit is contained in:
2026-07-15 20:38:54 +02:00
parent 1165cfb7c0
commit c4fa8e930f
9 changed files with 807 additions and 99 deletions
+126 -7
View File
@@ -2461,7 +2461,10 @@ main func(init process.Init) void {
io.print(writer, "{d}", {"bro",}) catch |_| {}
io.print(writer, "{d}{d}", {1,}) catch |_| {}
io.print(writer, "{d}", {1, 2}) catch |_| {}
io.print(writer, "{x}", {}) catch |_| {}
io.print(writer, "{q}", {}) catch |_| {}
io.print(writer, "{b}", {1.5,}) catch |_| {}
io.print(writer, "{e}", {1,}) catch |_| {}
io.print(writer, "{c}", {i16(65),}) catch |_| {}
io.print(writer, "}", {}) catch |_| {}
}
`
@@ -2481,16 +2484,19 @@ main func(init process.Init) void {
hir_module := checker.check(&ast_module, &diagnostics, &symbols)
defer hir.destroy_module(&hir_module)
found := [7]bool{}
found := [10]bool{}
for diagnostic in diagnostics.items {
message := diagnostic.message
found[0] = found[0] || strings.contains(message, "arguments must be a tuple")
found[1] = found[1] || strings.contains(message, "cannot implicitly convert i8 to []u8")
found[2] = found[2] || strings.contains(message, "'{d}' requires an integer")
found[2] = found[2] || strings.contains(message, "'{d}' requires an integer or float")
found[3] = found[3] || strings.contains(message, "argument count does not match")
found[4] = found[4] || strings.contains(message, "unknown specifier")
found[5] = found[5] || strings.contains(message, "unmatched '}'")
found[6] = found[6] || strings.contains(message, "compile-time-only metadata")
found[7] = found[7] || strings.contains(message, "integer format requires an integer argument")
found[8] = found[8] || strings.contains(message, "float format requires a float argument")
found[9] = found[9] || strings.contains(message, "'{c}' requires an unsigned integer that fits in u8")
}
testing.expect(t, loaded)
for present in found {
@@ -2498,6 +2504,121 @@ main func(init process.Init) void {
}
}
@(test)
milestone_39_stable_values_and_richer_formatting_compile_and_run :: proc(t: ^testing.T) {
stable_names: [dynamic]string
defer {
for name in stable_names {
delete(name)
}
delete(stable_names)
}
for pass := 0; pass < 2; pass += 1 {
sources := source.init_store()
diagnostics := source.init_store_diagnostics(&sources)
symbols := symbol.init_table()
ast_module, loaded := loader.load(
"examples/programs/milestone_39", &sources, &diagnostics, &symbols, project_root_path=".",
)
hir_module := checker.check(&ast_module, &diagnostics, &symbols)
ir_module := lower.lower(&hir_module)
llvm_text := llvm.emit(&ir_module, &diagnostics, &symbols)
score_count := 0
for function in hir_module.functions {
if strings.contains(function.link_name, "bro__p0__score__ca") {
if pass == 0 {
append(&stable_names, strings.clone(function.link_name))
} else {
testing.expect_value(t, function.link_name, stable_names[score_count])
}
score_count += 1
}
}
testing.expect(t, loaded)
testing.expect_value(t, len(diagnostics.items), 0)
testing.expect_value(t, score_count, 2)
testing.expect_value(t, count_substring_occurrences(llvm_text, "define internal fastcc i32 @bro__p0__read_carrier__"), 1)
testing.expect(t, !strings.contains(llvm_text, "FormatToken"))
testing.expect(t, !strings.contains(llvm_text, "parse_format"))
testing.expect(t, !strings.contains(llvm_text, "FieldInfo"))
testing.expect(t, !strings.contains(llvm_text, "EnumInfo"))
delete(llvm_text)
ir.destroy_module(&ir_module)
hir.destroy_module(&hir_module)
ast.destroy_module(&ast_module)
symbol.destroy_table(&symbols)
source.destroy_diagnostics(&diagnostics)
source.destroy_store(&sources)
}
output := "/tmp/brolang-test-milestone-39"
defer _ = os.remove(output)
status := compiler_core.compile_package(
"examples/programs/milestone_39", output, nil, target.DEFAULT, cimport.Options{}, ".",
)
testing.expect_value(t, status, 0)
state, stdout, stderr, _ := os2.process_exec(
os2.Process_Desc{command=[]string{output}}, context.allocator,
)
defer delete(stdout)
defer delete(stderr)
testing.expect_value(t, state.exit_code, 0)
testing.expect_value(
t,
string(stdout),
"true -42 1.5 .running bro 2.5 1010 12 ff FF A 1.5000000000000000e+00 {} -9223372036854775808 0 inf nan 1.50000000e+00\n",
)
testing.expect_value(t, string(stderr), "debug=.idle 2a\n")
}
@(test)
milestone_39_rejects_values_without_stable_identity :: proc(t: ^testing.T) {
text := `BadUnion :: union { number i32, flag bool }
Config :: struct { value i32 }
identity func() i32 { return 1 }
reject_pointer func($value @i32) void {}
reject_function func($value @func() i32) void {}
reject_slice func($value []i32) void {}
reject_range func($value range) void {}
reject_union func($value BadUnion) void {}
reject_undefined func($value Config) void {}
stored i32 :: 1
items [2]i32 :: [1, 2]
main func() void {
reject_pointer(&stored)
reject_function(identity)
reject_slice(items[..])
reject_range(0..3)
reject_union(BadUnion {number = 1})
reject_undefined(Config {value = undefined})
}
`
source_file := source.Source{path="test.bro", text=text}
diagnostics := source.init_diagnostics(&source_file)
defer source.destroy_diagnostics(&diagnostics)
symbols := symbol.init_table()
defer symbol.destroy_table(&symbols)
stream := lexer.lex(&source_file, &diagnostics, &symbols)
defer delete(stream.items)
ast_module := parser.parse(&stream, &source_file, &diagnostics)
defer ast.destroy_module(&ast_module)
hir_module := checker.check(&ast_module, &diagnostics, &symbols)
defer hir.destroy_module(&hir_module)
found := 0
for diagnostic in diagnostics.items {
if strings.contains(diagnostic.message, "comptime argument has no stable comptime identity") {
found += 1
}
}
testing.expect(t, found >= 6)
}
@(test)
milestone_37_inline_loop_control_must_be_statically_resolvable :: proc(t: ^testing.T) {
text := `main func() void {
@@ -3327,12 +3448,13 @@ comptime_value_params_diagnose_invalid_uses :: proc(t: ^testing.T) {
tiny func($N u8) i32 {
return N
}
bad_type func($T bool) void {}
good_bool func($T bool) void {}
bad_use func($N usize) void {
N = 1
_ = &N
}
main func() void {
good_bool(true)
x usize = 4
_ = make(x)
_ = make()
@@ -3359,7 +3481,6 @@ main func() void {
found_extra := false
found_negative := false
found_range := false
found_bad_type := false
found_assignment := false
found_address := false
for diagnostic in diagnostics.items {
@@ -3369,7 +3490,6 @@ main func() void {
found_extra = found_extra || strings.contains(message, "has no unique complete argument mapping")
found_negative = found_negative || strings.contains(message, "integer constant -1 does not fit in usize")
found_range = found_range || strings.contains(message, "integer constant 300 does not fit in u8")
found_bad_type = found_bad_type || strings.contains(message, "requires type, a concrete integer type, or immutable []u8")
found_assignment = found_assignment || strings.contains(message, "cannot assign comptime parameter 'N'")
found_address = found_address || strings.contains(message, "'&' requires an addressable location")
}
@@ -3379,7 +3499,6 @@ main func() void {
testing.expect(t, found_extra)
testing.expect(t, found_negative)
testing.expect(t, found_range)
testing.expect(t, found_bad_type)
testing.expect(t, found_assignment)
testing.expect(t, found_address)
}