array reflection
This commit is contained in:
+219
-3
@@ -4990,6 +4990,10 @@ missing func() i32 {
|
||||
if true {
|
||||
}
|
||||
}
|
||||
escape_slice func() []i32 {
|
||||
values [2]mut i32 = [1, 2]
|
||||
return values[..]
|
||||
}
|
||||
GLOBAL :: 1
|
||||
main func() void {
|
||||
runtime i32 = 1
|
||||
@@ -5000,6 +5004,30 @@ main func() void {
|
||||
yield callback()
|
||||
}
|
||||
_ = $&GLOBAL
|
||||
_ = ${
|
||||
values [2]mut i32 = [1, 2]
|
||||
pointer *mut i32 :: (&values).ptr
|
||||
yield pointer
|
||||
}
|
||||
_ = ${
|
||||
values [2]mut i32 = [1, 2]
|
||||
yield values[1..].ptr
|
||||
}
|
||||
_ = ${
|
||||
values [2]mut i32 = [1, 2]
|
||||
yield &values[0]
|
||||
}
|
||||
_ = ${
|
||||
values [2]mut i32 = [1, 2]
|
||||
view []mut i32 = values[..]
|
||||
yield view
|
||||
}
|
||||
_ = ${
|
||||
values [2]mut i32 = [1, 2]
|
||||
view []i32 = values[1..]
|
||||
yield view
|
||||
}
|
||||
_ = $escape_slice()
|
||||
_ = $spin()
|
||||
_ = $missing()
|
||||
_ = ${
|
||||
@@ -5021,7 +5049,9 @@ main func() void {
|
||||
|
||||
found_runtime := false
|
||||
runtime_only_count := 0
|
||||
found_pointer := false
|
||||
pointer_errors := 0
|
||||
slice_errors := 0
|
||||
found_expired := false
|
||||
found_quota := false
|
||||
found_missing := false
|
||||
found_yield := false
|
||||
@@ -5029,14 +5059,18 @@ main func() void {
|
||||
message := diagnostic.message
|
||||
found_runtime = found_runtime || strings.contains(message, "unresolved comptime value 'runtime'")
|
||||
runtime_only_count += 1 if strings.contains(message, "runtime-only") else 0
|
||||
found_pointer = found_pointer || strings.contains(message, "comptime storage pointers and slices cannot materialize as runtime memory")
|
||||
pointer_errors += 1 if strings.contains(message, "only immutable pointers to whole comptime arrays can materialize as runtime memory") else 0
|
||||
slice_errors += 1 if strings.contains(message, "only immutable full-array comptime slices can materialize as runtime memory") else 0
|
||||
found_expired = found_expired || strings.contains(message, "expired storage")
|
||||
found_quota = found_quota || strings.contains(message, "comptime evaluation exceeded the step quota")
|
||||
found_missing = found_missing || strings.contains(message, "did not return a value")
|
||||
found_yield = found_yield || strings.contains(message, "comptime block must yield a value")
|
||||
}
|
||||
testing.expect(t, found_runtime)
|
||||
testing.expect(t, runtime_only_count >= 2)
|
||||
testing.expect(t, found_pointer)
|
||||
testing.expect(t, pointer_errors >= 4)
|
||||
testing.expect(t, slice_errors >= 2)
|
||||
testing.expect(t, found_expired)
|
||||
testing.expect(t, found_quota)
|
||||
testing.expect(t, found_missing)
|
||||
testing.expect(t, found_yield)
|
||||
@@ -14706,6 +14740,188 @@ std_meta_tests_compile_and_run :: proc(t: ^testing.T) {
|
||||
testing.expect_value(t, state.exit_code, 0)
|
||||
}
|
||||
|
||||
@(test)
|
||||
array_reflection_reports_child_and_logical_length :: proc(t: ^testing.T) {
|
||||
directory := "/tmp/brolang-test-array-reflection"
|
||||
main_path := "/tmp/brolang-test-array-reflection/main.bro"
|
||||
output := "/tmp/brolang-test-array-reflection-output"
|
||||
text := `meta :: import "@std/meta"
|
||||
|
||||
Alias :: alias [3]u16
|
||||
|
||||
matches func($Array, $Child type, $len usize) bool {
|
||||
match typeinfo!(Array) {
|
||||
.array |info|: return info.child == Child and info.len == len
|
||||
else: return false
|
||||
}
|
||||
}
|
||||
|
||||
main func() i32 {
|
||||
if !$(matches([4]i32, i32, 4)) { return 1 }
|
||||
if !$(matches([0]bool, bool, 0)) { return 2 }
|
||||
if !$(matches(Alias, u16, 3)) { return 3 }
|
||||
if !$(matches([2]mut i64, i64, 2)) { return 4 }
|
||||
if !$(matches([2;0]u8, u8, 2)) { return 5 }
|
||||
return 0
|
||||
}
|
||||
`
|
||||
_ = os2.remove_all(directory)
|
||||
defer _ = os2.remove_all(directory)
|
||||
defer _ = os.remove(output)
|
||||
testing.expect(t, os.make_directory(directory) == nil)
|
||||
testing.expect(t, os.write_entire_file(main_path, transmute([]byte)text))
|
||||
testing.expect_value(t, compiler_core.compile_package(
|
||||
directory, output, nil, target.DEFAULT, cimport.Options{}, ".",
|
||||
), 0)
|
||||
state := run_executable(output)
|
||||
testing.expect_value(t, state.exit_code, 0)
|
||||
}
|
||||
|
||||
@(test)
|
||||
static_string_map_infers_array_size_and_preserves_promoted_backing :: proc(t: ^testing.T) {
|
||||
directory := "/tmp/brolang-test-static-string-map"
|
||||
main_path := "/tmp/brolang-test-static-string-map/main.bro"
|
||||
output := "/tmp/brolang-test-static-string-map-output"
|
||||
text := `std :: import "@std"
|
||||
static_string_map :: import "@std/static_string_map"
|
||||
|
||||
TokenKind :: enum {
|
||||
keyword_if
|
||||
keyword_else
|
||||
keyword_for
|
||||
keyword_return
|
||||
keyword_while
|
||||
}
|
||||
|
||||
keywords std.StaticStringMap(TokenKind) = static_string_map.init([
|
||||
{"if", .keyword_if},
|
||||
{"else", .keyword_else},
|
||||
{"for", .keyword_for},
|
||||
{"return", .keyword_return},
|
||||
])
|
||||
fallback :: static_string_map.init(TokenKind, [
|
||||
{"while", .keyword_while},
|
||||
])
|
||||
empty std.StaticStringMap(TokenKind) = static_string_map.init([])
|
||||
numbers []i32 = ${
|
||||
values [3]mut i32 = [7, 8, 9]
|
||||
yield values[..]
|
||||
}
|
||||
|
||||
main func() i32 {
|
||||
if keywords.keys.len != 4 or keywords.values.len != 4 or keywords.len_indexes.len != 7 { return 1 }
|
||||
if keywords.min_len != 2 or keywords.max_len != 6 { return 17 }
|
||||
if empty.keys.len != 0 or empty.values.len != 0 or empty.len_indexes.len != 0 { return 18 }
|
||||
if numbers.len != 3 or numbers[0] != 7 or numbers[2] != 9 { return 19 }
|
||||
if static_string_map.get(&keywords, "if") |value| {
|
||||
if value != TokenKind.keyword_if { return 2 }
|
||||
} else { return 3 }
|
||||
if static_string_map.get(&keywords, "else") |value| {
|
||||
if value != TokenKind.keyword_else { return 4 }
|
||||
} else { return 5 }
|
||||
if static_string_map.get(&keywords, "for") |value| {
|
||||
if value != TokenKind.keyword_for { return 6 }
|
||||
} else { return 7 }
|
||||
if static_string_map.get(&keywords, "return") |value| {
|
||||
if value != TokenKind.keyword_return { return 8 }
|
||||
} else { return 9 }
|
||||
if static_string_map.get(&keywords, "no") |_| { return 10 }
|
||||
if static_string_map.get(&keywords, "four") |_| { return 11 }
|
||||
if static_string_map.get(&keywords, "x") |_| { return 12 }
|
||||
if static_string_map.get(&keywords, "longer-than-any-key") |_| { return 13 }
|
||||
if static_string_map.get(&empty, "if") |_| { return 14 }
|
||||
if static_string_map.get(&fallback, "while") |value| {
|
||||
if value != TokenKind.keyword_while { return 15 }
|
||||
} else { return 16 }
|
||||
return 0
|
||||
}
|
||||
`
|
||||
_ = os2.remove_all(directory)
|
||||
defer _ = os2.remove_all(directory)
|
||||
defer _ = os.remove(output)
|
||||
testing.expect(t, os.make_directory(directory) == nil)
|
||||
testing.expect(t, os.write_entire_file(main_path, transmute([]byte)text))
|
||||
testing.expect_value(t, compiler_core.compile_package(
|
||||
directory, output, nil, target.DEFAULT, cimport.Options{}, ".",
|
||||
), 0)
|
||||
state := run_executable(output)
|
||||
testing.expect_value(t, state.exit_code, 0)
|
||||
}
|
||||
|
||||
@(test)
|
||||
static_string_map_reports_duplicate_and_malformed_entries :: proc(t: ^testing.T) {
|
||||
directory := "/tmp/brolang-test-static-string-map-errors"
|
||||
main_path := "/tmp/brolang-test-static-string-map-errors/main.bro"
|
||||
_ = os2.remove_all(directory)
|
||||
defer _ = os2.remove_all(directory)
|
||||
testing.expect(t, os.make_directory(directory) == nil)
|
||||
|
||||
duplicate_text := `std :: import "@std"
|
||||
static_string_map :: import "@std/static_string_map"
|
||||
TokenKind :: enum { keyword_if, keyword_else }
|
||||
bad std.StaticStringMap(TokenKind) = static_string_map.init([
|
||||
{"if", .keyword_if},
|
||||
{"if", .keyword_else},
|
||||
])
|
||||
main func() void {}
|
||||
`
|
||||
testing.expect(t, os.write_entire_file(main_path, transmute([]byte)duplicate_text))
|
||||
{
|
||||
sources := source.init_store()
|
||||
defer source.destroy_store(&sources)
|
||||
diagnostics := source.init_store_diagnostics(&sources)
|
||||
defer source.destroy_diagnostics(&diagnostics)
|
||||
symbols := symbol.init_table()
|
||||
defer symbol.destroy_table(&symbols)
|
||||
module, loaded := loader.load(directory, &sources, &diagnostics, &symbols, project_root_path=".")
|
||||
defer ast.destroy_module(&module)
|
||||
hir_module := checker.check(&module, &diagnostics, &symbols)
|
||||
defer hir.destroy_module(&hir_module)
|
||||
testing.expect(t, loaded)
|
||||
found := false
|
||||
for diagnostic in diagnostics.items {
|
||||
found = found || strings.contains(diagnostic.message, "duplicate static string map key")
|
||||
}
|
||||
testing.expect(t, found)
|
||||
}
|
||||
|
||||
malformed_text := `std :: import "@std"
|
||||
static_string_map :: import "@std/static_string_map"
|
||||
TokenKind :: enum { keyword_if }
|
||||
bad std.StaticStringMap(TokenKind) = static_string_map.init([
|
||||
{123, .keyword_if},
|
||||
])
|
||||
bad_value std.StaticStringMap(TokenKind) = static_string_map.init([
|
||||
{"if", "bad"},
|
||||
])
|
||||
main func() void {}
|
||||
`
|
||||
testing.expect(t, os.write_entire_file(main_path, transmute([]byte)malformed_text))
|
||||
{
|
||||
sources := source.init_store()
|
||||
defer source.destroy_store(&sources)
|
||||
diagnostics := source.init_store_diagnostics(&sources)
|
||||
defer source.destroy_diagnostics(&diagnostics)
|
||||
symbols := symbol.init_table()
|
||||
defer symbol.destroy_table(&symbols)
|
||||
module, loaded := loader.load(directory, &sources, &diagnostics, &symbols, project_root_path=".")
|
||||
defer ast.destroy_module(&module)
|
||||
hir_module := checker.check(&module, &diagnostics, &symbols)
|
||||
defer hir.destroy_module(&hir_module)
|
||||
testing.expect(t, loaded)
|
||||
found_key := false
|
||||
found_value := false
|
||||
for diagnostic in diagnostics.items {
|
||||
found_key = found_key || strings.contains(diagnostic.message, "cannot implicitly convert i8 to []u8 at comptime")
|
||||
found_value = found_value ||
|
||||
strings.contains(diagnostic.message, "cannot implicitly convert") &&
|
||||
strings.contains(diagnostic.message, "to TokenKind at comptime")
|
||||
}
|
||||
testing.expect(t, found_key)
|
||||
testing.expect(t, found_value)
|
||||
}
|
||||
}
|
||||
|
||||
@(test)
|
||||
noreturn_functions_function_pointers_and_peer_types_compile_and_run :: proc(t: ^testing.T) {
|
||||
directory := "/tmp/brolang-test-noreturn"
|
||||
|
||||
Reference in New Issue
Block a user