1501 lines
67 KiB
Plaintext
1501 lines
67 KiB
Plaintext
import "@std/mem"
|
|
import "@std/arraylist"
|
|
import "@std/testing"
|
|
import "@source/ast"
|
|
import "@source/diagnostics"
|
|
import "@source/ir"
|
|
import "@source/interpreter"
|
|
|
|
@hide:file
|
|
owned_text proc(text []u8) arraylist.ArrayList(u8) ! mem.AllocError {
|
|
bytes := arraylist.init(u8, mem.c_allocator)
|
|
errdefer arraylist.deinit(&bytes)
|
|
try arraylist.reserve(&bytes, text.len)
|
|
for (text) |byte| try arraylist.append(&bytes, byte)
|
|
return bytes
|
|
}
|
|
|
|
keeps_package_declarations_distinct_and_ir_independent test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
first := try owned_text("value :: 21\nmain proc() int { return value * 2 }")
|
|
defer arraylist.deinit(&first)
|
|
second := try owned_text("value :: 3\nmain proc() int { return value * 2 }")
|
|
defer arraylist.deinit(&second)
|
|
sibling := try owned_text("helper proc() int { return 7 }")
|
|
defer arraylist.deinit(&sibling)
|
|
path [9]mut u8 := undefined
|
|
memcopy!(path[..], "first.hon")
|
|
session := init(mem.c_allocator)
|
|
# the IR must outlive the compilation, including source buffers and interned names.
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
dependency :: try add_package(&session)
|
|
left :: try add_source(&session, root, path[..], &first, &diagnostic_store)
|
|
right :: try add_source(&session, dependency, "second.hon", &second, &diagnostic_store)
|
|
third :: try add_source(&session, root, "sibling.hon", &sibling, &diagnostic_store)
|
|
path[0] = 'X'
|
|
try testing.expect_equal(0, first.capacity)
|
|
try testing.expect_equal(0, first.items.len)
|
|
try testing.expect(mem.eql(source(&session, left).path, "first.hon"))
|
|
try testing.expect_equal(root, source(&session, left).package)
|
|
try testing.expect_equal(dependency, source(&session, right).package)
|
|
try testing.expect_equal(root, source(&session, third).package)
|
|
try testing.expect_equal(left, session.packages.items[usize(root)].sources.items[0])
|
|
try testing.expect_equal(third, session.packages.items[usize(root)].sources.items[1])
|
|
a :: declaration(&session, left, 0)
|
|
b :: declaration(&session, right, 0)
|
|
try testing.expect(a.source != b.source)
|
|
tree :: ast.view(&session.builder, source(&session, left).root)
|
|
try testing.expect_equal(ast.name_id(&tree, a.node), ast.name_id(&tree, b.node))
|
|
try testing.expect(mem.eql(ast.source_text(&tree, ast.statement_decl(&tree, a.node).span), "value :: 21"))
|
|
try testing.expect(mem.eql(ast.source_text(&tree, ast.statement_decl(&tree, b.node).span), "value :: 3"))
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, dependency, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
left_result := try interpreter.run(mem.c_allocator, &modules[0], &diagnostic_store)
|
|
defer interpreter.deinit(&left_result)
|
|
right_result := try interpreter.run(mem.c_allocator, &modules[1], &diagnostic_store)
|
|
defer interpreter.deinit(&right_result)
|
|
try testing.expect(left_result.trap == null and right_result.trap == null)
|
|
try testing.expect_equal(i64(42), left_result.value.data.integer)
|
|
try testing.expect_equal(i64(6), right_result.value.data.integer)
|
|
}
|
|
|
|
recompiles_specialized_calls_without_borrowing_previous_ir test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
bytes := try owned_text(
|
|
`identity proc($T type, value T) T {
|
|
` if (T == i16) return value else return value.missing
|
|
`}
|
|
`Box proc(T type) type { return struct { value T } }
|
|
`make_box proc($T type) Box(T) { return { value = 40 } }
|
|
`count proc() usize {
|
|
` result := 0
|
|
` while (result < 2) result = result + 1
|
|
` return result
|
|
`}
|
|
`Fixed proc(N usize) type {
|
|
` Element := i8
|
|
` length usize := 0
|
|
` while (length < N) {
|
|
` match length { 0: Element = i16, else: Element = i16 }
|
|
` length = length + 1
|
|
` }
|
|
` return match length {
|
|
` 2: struct {
|
|
` values [match length { 2: length, else: usize(1) }](match true {
|
|
` true: Element,
|
|
` false: i8(128),
|
|
` })
|
|
` bias i16 = match true { true: 0, false: i8(128) }
|
|
` },
|
|
` else: i8(128),
|
|
` }
|
|
`}
|
|
`data proc() [2]i16 { return [40, 2] }
|
|
`Tag :: enum(i16) { empty = -7, payload = 90 }
|
|
`Choice :: union(Tag) { payload struct { values [2]i16, text string }, empty void }
|
|
`Error :: union(enum) { failed struct { code i16, text string } }
|
|
`Packet :: struct { choices [2]Choice, results [2](i16 ! Error) }
|
|
`packet_data proc() Packet {
|
|
` return {
|
|
` choices = [.payload { values = [40, 2], text = "ok" }, .empty],
|
|
` results = [40, .failed { code = 2, text = "owned" }],
|
|
` }
|
|
`}
|
|
`Token proc($value Packet) type { return struct {} }
|
|
`Captured proc(choice Choice) type {
|
|
` match choice {
|
|
` .payload |detail|: return struct {
|
|
` values [match detail.text.len { 2: usize(2), else: usize(0) }]i16
|
|
` bias i16 = match choice { .payload |selected|: selected.values[1], .empty: 0 }
|
|
` },
|
|
` .empty: return bool,
|
|
` }
|
|
`}
|
|
`Optional proc() type {
|
|
` pending ?usize := 2
|
|
` Result := i8
|
|
` while pending |length| {
|
|
` pending = null
|
|
` Result = [length]i16
|
|
` }
|
|
` return Result
|
|
`}
|
|
`Updated proc() type {
|
|
` config struct { counts [2]mut usize, bias i16 } := { counts = [0, 0], bias = 0 }
|
|
` original :: config
|
|
` for (usize(0)..2) |index| {
|
|
` field!(config, "counts")[index] = index + 1
|
|
` field!(config, "bias") = field!(config, "bias") + 21
|
|
` }
|
|
` return struct {
|
|
` values [config.counts[1]]i16
|
|
` bias i16 = config.bias + i16(original.counts[1])
|
|
` }
|
|
`}
|
|
`Collected proc() type {
|
|
` counts [2]mut usize := [1, 1]
|
|
` length usize := 0
|
|
` for counts |amount, index| {
|
|
` counts[1] = 2
|
|
` length = length + amount
|
|
` if (index == 0) continue
|
|
` }
|
|
` Element := i8
|
|
` for "ok" |byte| { if (byte == u8(107)) Element = i16 }
|
|
` return [length]Element
|
|
`}
|
|
`TypeArray proc() type {
|
|
` types [2]mut [1]mut type := [[i8], [bool]]
|
|
` original :: types
|
|
` for types |row, index| {
|
|
` copied := row
|
|
` copied[0] = u8
|
|
` if (row[0] == u8) return bool
|
|
` if (index == 0) { (types[1])[0] = i16 }
|
|
` if (index == 1 and row[0] != i16) return bool
|
|
` }
|
|
` if (original[1][0] != bool) return bool
|
|
` inferred := [[i8], [bool]]
|
|
` inferred = [[i16], [u8]]
|
|
` empty [0]type :: []
|
|
` for (empty) |_| return bool
|
|
` return struct { values [types.len]types[1][0], bias inferred[0][0] = 2 }
|
|
`}
|
|
`TypeRows proc() [2]mut [1]mut type {
|
|
` rows [2]mut [1]mut type := [[i8], [i16]]
|
|
` (rows[0])[0] = i16
|
|
` return rows
|
|
`}
|
|
`copy_type_rows proc(rows [2]mut [1]mut type) [2]mut [1]mut type {
|
|
` copied := rows
|
|
` (copied[0])[0] = u8
|
|
` if (rows[0][0] != i16) return [[bool], [bool]]
|
|
` return copied
|
|
`}
|
|
`BoundaryType proc(rows [2]mut [1]mut type) type {
|
|
` original :: rows
|
|
` changed :: copy_type_rows(rows)
|
|
` if (changed[0][0] != u8 or rows[0][0] != i16 or original[0][0] != i16) return bool
|
|
` return struct { values [rows.len]rows[0][0], bias rows[1][0] = 2 }
|
|
`}
|
|
`read_type_rows proc($rows [2]mut [1]mut type, value rows[0][0]) rows[1][0] {
|
|
` return value + rows[1][0](rows.len)
|
|
`}
|
|
`UninitializedRows proc() [2]mut type {
|
|
` types [2]mut type := undefined
|
|
` for (usize(0)..types.len) |index| {
|
|
` if (index == 0) { types[index] = struct { value i16 } }
|
|
` else { types[index] = types[0] }
|
|
` }
|
|
` return types
|
|
`}
|
|
`UninitializedType proc(types [2]mut type) type {
|
|
` return struct { first types[0], second types[1] }
|
|
`}
|
|
`UninitializedValues proc() type {
|
|
` rows [2]mut [2]mut usize := undefined
|
|
` (rows[0])[0] = 1
|
|
` copied := rows
|
|
` rows[0] = [3, 4]
|
|
` (copied[0])[1] = 2
|
|
` copied[1] = [1, 1]
|
|
` for (usize(0)..rows[1].len) |index| { (rows[1])[index] = index + 1 }
|
|
` return struct {
|
|
` values [copied[0][1]]i16
|
|
` bias i16 = i16(copied[1][0] + rows[1][0])
|
|
` }
|
|
`}
|
|
`TypeRecord proc() type {
|
|
` Config :: struct { child type, counts [2]mut usize, bias i16 = 2 }
|
|
` config Config := { child = i8, counts = [0, 0] }
|
|
` original :: config
|
|
` config.child = i16
|
|
` for config.counts |_, index| { config.counts[index] = index + 1 }
|
|
` if (original.child != i8 or original.counts[1] != 0) return bool
|
|
` return struct { values [config.counts[1]]config.child, bias i16 = config.bias }
|
|
`}
|
|
`BoundaryConfig :: struct { child type, counts [2]mut usize, bias i16 = 2 }
|
|
`record_config proc() BoundaryConfig { return { child = i16, counts = [1, 2] } }
|
|
`partial_record_config proc() BoundaryConfig {
|
|
` config BoundaryConfig := undefined
|
|
` config.child = i8
|
|
` config.counts[0] = 1
|
|
` copied := config
|
|
` config.child = bool
|
|
` copied.child = i16
|
|
` copied.counts[1] = 2
|
|
` copied.bias = 2
|
|
` return copied
|
|
`}
|
|
`change_record_config proc(input BoundaryConfig) BoundaryConfig {
|
|
` copied := input
|
|
` copied.child = u8
|
|
` copied.counts[1] = 3
|
|
` return copied
|
|
`}
|
|
`RecordBoundary proc(input BoundaryConfig) type {
|
|
` changed :: change_record_config(input)
|
|
` if (input.child != i16 or input.counts[1] != 2) return bool
|
|
` if (changed.child != u8 or changed.counts[1] != 3) return bool
|
|
` return struct { values [input.counts[1]]input.child, bias i16 = input.bias }
|
|
`}
|
|
`RecordAlias :: alias RecordBoundary(record_config())
|
|
`read_record_config proc($input BoundaryConfig, value input.child) input.child {
|
|
` return value + input.bias
|
|
`}
|
|
`record_pair proc() struct { type, usize } { return {i16, 2} }
|
|
`RecordPairElement proc(input struct { type, usize }) type { return field!(input, "0") }
|
|
`read_record_pair proc($input struct { type, usize }, value RecordPairElement(input)) RecordPairElement(input) {
|
|
` return value + i16(field!(input, "1"))
|
|
`}
|
|
`read_selected proc($choice Choice, value i16) i16 {
|
|
` match choice {
|
|
` .payload |detail|: {
|
|
` copied :: detail
|
|
` if (copied.text.len != 2) return -1
|
|
` return match detail.values[1] {
|
|
` 2: match true { true: value + detail.values[1], false: value.missing },
|
|
` else: value.missing,
|
|
` }
|
|
` }
|
|
` .empty: return value.missing,
|
|
` }
|
|
`}
|
|
`main proc() i16 {
|
|
` if $(i16 != i16) { return $(i8(128)) }
|
|
` values :: $(data())
|
|
` box Box(i16) :: make_box()
|
|
` inferred i16 :: identity(40)
|
|
` if (inferred != box.value) return 0
|
|
` fixed Fixed(count()) :: { values = [box.value, 2] }
|
|
` same Fixed(2) :: fixed
|
|
` packet :: $(packet_data())
|
|
` if (Token(packet_data()) != Token(packet)) return 0
|
|
` captured Captured(packet.choices[0]) :: { values = [19, 21] }
|
|
` if (captured.values[0] + captured.values[1] + captured.bias != 42) return 0
|
|
` optional Optional() :: captured.values
|
|
` if (optional[0] + optional[1] != 40) return 0
|
|
` updated Updated() :: { values = optional }
|
|
` if (updated.bias != 42 or updated.values[1] != 21) return 0
|
|
` collected Collected() :: [19, 21, 2]
|
|
` same_collected Collected() :: collected
|
|
` total i16 := 0
|
|
` for same_collected |item| { total = total + item }
|
|
` if (total != 42) return 0
|
|
` type_array TypeArray() :: { values = [19, 21] }
|
|
` same_type_array TypeArray() :: type_array
|
|
` if (same_type_array.values[0] + same_type_array.values[1] + same_type_array.bias != 42) return 0
|
|
` boundary BoundaryType(TypeRows()) :: { values = [19, 21] }
|
|
` same_boundary BoundaryType(TypeRows()) :: boundary
|
|
` if (same_boundary.values[0] + same_boundary.values[1] + field!(same_boundary, "bias") != 42) return 0
|
|
` if (copy_type_rows(TypeRows())[0][0] != u8 or copy_type_rows(TypeRows())[1][0] != i16) return 0
|
|
` if (TypeRows()[0][0] != i16) return 0
|
|
` if (read_type_rows(TypeRows(), 40) != 42 or read_type_rows(TypeRows(), 40) != 42) return 0
|
|
` initialized UninitializedType(UninitializedRows()) :: {
|
|
` first = { value = 19 }, second = { value = 21 },
|
|
` }
|
|
` same_initialized UninitializedType(UninitializedRows()) :: initialized
|
|
` copied_initialized := same_initialized.first
|
|
` initialized_values UninitializedValues() :: { values = [19, 21] }
|
|
` same_initialized_values UninitializedValues() :: initialized_values
|
|
` if (same_initialized_values.values[0] + same_initialized_values.values[1] + same_initialized_values.bias != 42) return 0
|
|
` type_record TypeRecord() :: { values = [19, 21] }
|
|
` same_type_record TypeRecord() :: type_record
|
|
` if (same_type_record.values[0] + same_type_record.values[1] + same_type_record.bias != 42) return 0
|
|
` record_boundary RecordAlias :: { values = [19, 21] }
|
|
` same_record_boundary RecordBoundary({ child = i16, counts = [1, 2] }) :: record_boundary
|
|
` if (same_record_boundary.values[0] + same_record_boundary.values[1] + same_record_boundary.bias != 42) return 0
|
|
` if (read_record_config(record_config(), 40) != 42) return 0
|
|
` partial_boundary RecordBoundary(partial_record_config()) :: record_boundary
|
|
` if (partial_boundary.values[0] + partial_boundary.values[1] + partial_boundary.bias != 42) return 0
|
|
` if (read_record_config(partial_record_config(), 40) != 42) return 0
|
|
` if (read_record_pair(record_pair(), 40) != 42 or read_record_pair(record_pair(), 40) != 42) return 0
|
|
` copied_initialized = same_initialized.second
|
|
` payload :: packet.choices[0].payload
|
|
` if (payload.values[0] != 40 or payload.values[1] != 2 or payload.text.len != 2) return 0
|
|
` match packet.choices[1] { .empty: {}, .payload: return 0 }
|
|
` if ((packet.results[0] catch 0) != 40) return 0
|
|
` error_code :: packet.results[1] catch |err| match err {
|
|
` .failed |detail|: detail.code + i16(detail.text.len),
|
|
` }
|
|
` if (error_code != 7) return 0
|
|
` return read_selected(packet.choices[0], identity(initialized.first.value) + copied_initialized.value + same.values[$(usize(1))] + same.bias - 2)
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&bytes)
|
|
_ = try add_source(&session, root, "generic.hon", &bytes, &diagnostic_store)
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for (0..modules.len) |index| {
|
|
outcome := try interpreter.run(mem.c_allocator, &modules[index], &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
}
|
|
|
|
recompiles_imported_inline_for_without_retaining_expansions test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
dependency :: try add_package(&session)
|
|
root_bytes := try owned_text(
|
|
`dep :: import "../dependency"
|
|
`touch proc(value i16) i16 { return value }
|
|
`main proc() i16 {
|
|
` total i16 := 0
|
|
` inline for dep.values() |value, index| {
|
|
` at usize :: index
|
|
` total = total + touch(value) + i16(at)
|
|
` }
|
|
` inline for dep.types() |T| {
|
|
` if (T == i16) {
|
|
` value T :: total
|
|
` total = touch(value)
|
|
` } else {
|
|
` value T :: true
|
|
` if (!value) return 0
|
|
` }
|
|
` }
|
|
` inline for dep.metadata() |item, index| {
|
|
` if (index == 0) {
|
|
` if (item != i16) return 0
|
|
` } else if (index == 1) {
|
|
` exact i8 :: item
|
|
` if (exact != 42) return 0
|
|
` } else if (item.len != 2) return 0
|
|
` }
|
|
` inline for (i8(0)..i8(2)) |outer| {
|
|
` inline for [i8(0), i8(1)] |inner| {
|
|
` for (0..usize(2)) |index| {
|
|
` if (index == 0) continue
|
|
` total = total + i16(outer + inner)
|
|
` }
|
|
` }
|
|
` }
|
|
` return total
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&root_bytes)
|
|
dependency_bytes := try owned_text(
|
|
`values proc() [2]i16 { return [17, 20] }
|
|
`types proc() [2]type { return [i16, bool] }
|
|
`metadata proc() struct { type, i8, string } { return {i16, 42, "ok"} }
|
|
,
|
|
)
|
|
defer arraylist.deinit(&dependency_bytes)
|
|
root_source :: try add_source(&session, root, "app/main.hon", &root_bytes, &diagnostic_store)
|
|
_ = try add_source(&session, dependency, "dependency/values.hon", &dependency_bytes, &diagnostic_store)
|
|
try arraylist.append(&session.imports, Import{
|
|
node = declaration(&session, root_source, 0).node,
|
|
target = dependency,
|
|
})
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for (0..modules.len) |index| {
|
|
outcome := try interpreter.run(mem.c_allocator, &modules[index], &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
}
|
|
|
|
recompiles_imported_inline_match_arms_without_retaining_expansions test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
dependency :: try add_package(&session)
|
|
root_bytes := try owned_text(
|
|
`dep :: import "../dependency"
|
|
`known proc($tag dep.Mode) i16 {
|
|
` if (tag == .answer) return 0 else return false
|
|
`}
|
|
`enum_score proc(input dep.Mode) i16 {
|
|
` return match input { .skip: 0, inline |tag|: known(tag) }
|
|
`}
|
|
`main proc() i16 {
|
|
` values :: dep.values()
|
|
` if (enum_score(.skip) + enum_score(dep.mode()) != 0) return -1
|
|
` if (dep.error_score(.Failure{code = 42}) + dep.error_score(.missing) != 42) return -2
|
|
` return (
|
|
` dep.read(dep.Choice, values[0]) + dep.read(dep.Choice, values[1])
|
|
` + dep.read(dep.Choice, values[2]) + dep.read(dep.Choice, values[3])
|
|
` )
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&root_bytes)
|
|
dependency_bytes := try owned_text(
|
|
`Mode :: enum(i16) { skip = -7, answer = 42 }
|
|
`Tag :: enum(i16) { number = -7, record = 3, text = 42, empty = 90 }
|
|
`Pair :: struct { values [2]i16 }
|
|
`Choice :: union(Tag) { text string, empty void, number i8, record Pair }
|
|
`Missing :: enum { missing }
|
|
`Failure :: struct { code i16 }
|
|
`Errors :: alias (Missing | Failure | Missing)
|
|
`fail proc(input Errors) i16 ! Errors { return input }
|
|
`error_score proc(input Errors) i16 {
|
|
` return fail(input) catch |err| match err {
|
|
` inline |payload, tag|: match tag { .Failure: payload.code, else: 0 },
|
|
` }
|
|
`}
|
|
`mode proc() Mode { return .answer }
|
|
`values proc() [4]Choice {
|
|
` return [.number{19}, .record{values = [9, 11]}, .text{"ok"}, .empty]
|
|
`}
|
|
`narrow proc(value i8) i16 { return i16(value) }
|
|
`pair proc(value Pair) i16 { return value.values[0] + value.values[1] }
|
|
`read proc($T type, input T) i16 {
|
|
` match input {
|
|
` inline |payload, tag|: {
|
|
` match tag {
|
|
` inline |selected|: {
|
|
` if (selected == .number) { return narrow(payload) }
|
|
` else if (selected == .record) { return pair(payload) }
|
|
` else if (selected == .text) { return i16(payload.len) }
|
|
` else {
|
|
` payload
|
|
` return 1
|
|
` }
|
|
` },
|
|
` }
|
|
` },
|
|
` }
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&dependency_bytes)
|
|
root_source :: try add_source(&session, root, "app/main.hon", &root_bytes, &diagnostic_store)
|
|
_ = try add_source(&session, dependency, "dependency/values.hon", &dependency_bytes, &diagnostic_store)
|
|
try arraylist.append(&session.imports, Import{
|
|
node = declaration(&session, root_source, 0).node,
|
|
target = dependency,
|
|
})
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for (0..modules.len) |index| {
|
|
outcome := try interpreter.run(mem.c_allocator, &modules[index], &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
}
|
|
|
|
recompiles_generated_records_without_borrowing_previous_ir test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
bytes := try owned_text(
|
|
`Child proc(value i16) type {
|
|
` return struct_type!(.auto, ["value"], [i16], [value])
|
|
`}
|
|
`Parent proc(value i16) type {
|
|
` ChildType :: Child(value)
|
|
` child ChildType :: {}
|
|
` return struct_type!(
|
|
` .auto,
|
|
` ["child", "bias", "text"],
|
|
` [ChildType, i16, string],
|
|
` [child, 2, "owned"],
|
|
` )
|
|
`}
|
|
`Captured proc(value ?i16) type {
|
|
` return if value |payload| struct { value i16 = payload } else bool
|
|
`}
|
|
`selected proc($value ?i16) i16 {
|
|
` return if $(value) |payload| payload else 7
|
|
`}
|
|
`main proc() i16 {
|
|
` parent Parent(40) :: {}
|
|
` captured Captured(40) :: {}
|
|
` absent Captured(null) :: false
|
|
` if (absent or captured.value != selected(40) or selected(null) != 7) return 0
|
|
` same Parent(40) :: parent
|
|
` child Child(40) :: same.child
|
|
` if (Child(40) == Child(41) or Parent(40) == Parent(41)) return 0
|
|
` other Parent(41) :: {}
|
|
` if (other.child.value != 41 or same.text.len != 5) return 0
|
|
` return child.value + same.bias
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&bytes)
|
|
_ = try add_source(&session, root, "generated.hon", &bytes, &diagnostic_store)
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for (0..modules.len) |index| {
|
|
outcome := try interpreter.run(mem.c_allocator, &modules[index], &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
}
|
|
|
|
recompiles_imported_typeinfo_without_borrowing_metadata test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
metadata :: try add_package(&session)
|
|
root_bytes := try owned_text(
|
|
`meta :: import "@std/meta"
|
|
`Id :: distinct i16
|
|
`Keys :: enum { left, right }
|
|
`Source :: struct { value Id }
|
|
`describe proc($T type) meta.TypeInfo { return typeinfo!(T) }
|
|
`identity proc($T type, value T) T { return value }
|
|
`Storage proc() type {
|
|
` match describe(Keys) {
|
|
` .enum |info|: {
|
|
` names [info.fields.len]mut []u8 := undefined
|
|
` types [info.fields.len]mut type := undefined
|
|
` defaults [info.fields.len]mut ?Id := undefined
|
|
` inline for info.fields |field, index| {
|
|
` if (field.index != index or field.type != Keys) compile_error!("invalid enum field")
|
|
` names[index] = field.name
|
|
` types[index] = Id
|
|
` defaults[index] = Id(40)
|
|
` }
|
|
` return struct_type!(.auto, names, types, defaults)
|
|
` }
|
|
` else: compile_error!("expected enum")
|
|
` }
|
|
`}
|
|
`main proc() i16 {
|
|
` match describe([2]Id) {
|
|
` .array |info|: {
|
|
` if (info.child != Id or info.len != 2) return 0
|
|
` }
|
|
` else: return 0
|
|
` }
|
|
` match describe(Id) {
|
|
` .distinct |backing|: if (backing != i16) return 0
|
|
` else: return 0
|
|
` }
|
|
` match describe(Source) {
|
|
` .record |info|: {
|
|
` if (info.fields.len != 1 or info.is_tuple or info.layout != .auto) return 0
|
|
` inline for info.fields |field, index| {
|
|
` if (field.type != Id or field.index != index or field.name.len != 5) return 0
|
|
` }
|
|
` }
|
|
` else: return 0
|
|
` }
|
|
` storage Storage() :: {}
|
|
` left Id :: identity(Id, storage.left)
|
|
` right Id :: identity(Id, storage.right)
|
|
` return i16(left) + i16(right) - 38
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&root_bytes)
|
|
metadata_bytes := try owned_text(
|
|
`Layout :: enum { auto, c }
|
|
`ArrayInfo :: struct { child type, len usize }
|
|
`FieldInfo :: struct { name []u8, type type, index usize }
|
|
`RecordInfo :: struct { name ?[]u8, fields []FieldInfo, is_tuple bool, layout Layout }
|
|
`EnumInfo :: struct { fields []FieldInfo }
|
|
`TypeInfo :: union(enum) {
|
|
` invalid void
|
|
` void void
|
|
` noreturn void
|
|
` anyopaque void
|
|
` bool void
|
|
` integer void
|
|
` float void
|
|
` array ArrayInfo
|
|
` pointer void
|
|
` slice void
|
|
` range void
|
|
` optional void
|
|
` function void
|
|
` enum EnumInfo
|
|
` record RecordInfo
|
|
` union void
|
|
` fallible void
|
|
` distinct type
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&metadata_bytes)
|
|
root_source :: try add_source(&session, root, "app/main.hon", &root_bytes, &diagnostic_store)
|
|
_ = try add_source(&session, metadata, "std/meta/meta.hon", &metadata_bytes, &diagnostic_store)
|
|
try arraylist.append(&session.imports, Import{
|
|
node = declaration(&session, root_source, 0).node,
|
|
target = metadata,
|
|
})
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for (0..modules.len) |index| {
|
|
outcome := try interpreter.run(mem.c_allocator, &modules[index], &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
}
|
|
|
|
dependency_traps_keep_original_spans_and_remain_demand_driven test {
|
|
mains [2][]u8 :: [
|
|
`dep :: import "../dependency"
|
|
`main proc() int { return dep.fail(false) }
|
|
`
|
|
,
|
|
`dep :: import "../dependency"
|
|
`main proc() int { return dep.fail(true) }
|
|
`
|
|
,
|
|
]
|
|
prefix ::
|
|
`
|
|
`fail proc(take bool) int {
|
|
` if take {
|
|
`
|
|
for (mains) |main, index| {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
module ir.Module := undefined
|
|
dependency_source SourceId := undefined
|
|
original diagnostics.DiagnosticId := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
dependency :: try add_package(&session)
|
|
root_bytes := try owned_text(main)
|
|
defer arraylist.deinit(&root_bytes)
|
|
dependency_bytes := try owned_text(
|
|
`
|
|
`fail proc(take bool) int {
|
|
` if take {
|
|
` return missing
|
|
` }
|
|
` return 42
|
|
`}
|
|
`
|
|
,
|
|
)
|
|
defer arraylist.deinit(&dependency_bytes)
|
|
root_source :: try add_source(&session, root, "app/main.hon", &root_bytes, &diagnostic_store)
|
|
dependency_source = try add_source(&session, dependency, "dependency/fail.hon", &dependency_bytes, &diagnostic_store)
|
|
try arraylist.append(&session.imports, Import{
|
|
node = declaration(&session, root_source, 0).node,
|
|
target = dependency,
|
|
})
|
|
module = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&module)
|
|
try testing.expect_equal(1, diagnostics.count(&diagnostic_store))
|
|
original = diagnostics.DiagnosticId(0)
|
|
diagnostic :: diagnostics.get(&diagnostic_store, original)?
|
|
try testing.expect_equal(diagnostics.Code.unknown_name, diagnostic.code)
|
|
try testing.expect_equal(dependency_source, diagnostic.span.source)
|
|
start :: u32(prefix.len + " return ".len)
|
|
try testing.expect_equal(start, diagnostic.span.start)
|
|
try testing.expect_equal(start + 7, diagnostic.span.end)
|
|
outcome := try interpreter.run(mem.c_allocator, &module, &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect_equal(1, diagnostics.count(&diagnostic_store))
|
|
if (index == 0) {
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
} else {
|
|
try testing.expect_equal(original, outcome.trap?)
|
|
}
|
|
}
|
|
}
|
|
|
|
file_local_declarations_are_isolated_from_siblings_and_import_selection test {
|
|
callers [4][]u8 :: [
|
|
"dep :: import \"../dependency\"\nmain proc() int { return dep.answer() }\n",
|
|
"dep :: import \"../dependency\"\nmain proc() int { return dep.sibling() }\n",
|
|
"dep :: import \"../dependency\"\nmain proc() int { return dep.leak() }\n",
|
|
"dep :: import \"../dependency\"\nmain proc() int { return dep.helper() }\n",
|
|
]
|
|
for callers |caller, index| {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
dependency :: try add_package(&session)
|
|
root_bytes := try owned_text(caller)
|
|
defer arraylist.deinit(&root_bytes)
|
|
first_bytes := try owned_text(
|
|
`@hide:file
|
|
`helper proc() int { return 42 }
|
|
`@hide:file secret :: 7
|
|
`answer proc() int { return helper() }
|
|
,
|
|
)
|
|
defer arraylist.deinit(&first_bytes)
|
|
second_bytes := try owned_text(
|
|
`@hide:file
|
|
`helper proc() int { return 99 }
|
|
`sibling proc() int { return helper() }
|
|
`leak proc() int { return secret }
|
|
,
|
|
)
|
|
defer arraylist.deinit(&second_bytes)
|
|
root_source :: try add_source(&session, root, "app/main.hon", &root_bytes, &diagnostic_store)
|
|
_ = try add_source(&session, dependency, "dependency/first.hon", &first_bytes, &diagnostic_store)
|
|
_ = try add_source(&session, dependency, "dependency/second.hon", &second_bytes, &diagnostic_store)
|
|
try arraylist.append(&session.imports, Import{
|
|
node = declaration(&session, root_source, 0).node,
|
|
target = dependency,
|
|
})
|
|
module := try compile(&session, root, &diagnostic_store)
|
|
defer ir.deinit(&module)
|
|
outcome := try interpreter.run(mem.c_allocator, &module, &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
if (index < 2) {
|
|
try testing.expect(outcome.trap == null)
|
|
expected :: if (index == 0) i64(42) else i64(99)
|
|
try testing.expect_equal(expected, outcome.value.data.integer)
|
|
} else {
|
|
diagnostic :: diagnostics.get(&diagnostic_store, outcome.trap?)?
|
|
try testing.expect_equal(diagnostics.Code.unknown_name, diagnostic.code)
|
|
}
|
|
}
|
|
}
|
|
|
|
yielding_blocks_recompile_owned_constants_and_generated_types test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
bytes := try owned_text(
|
|
`Choose proc(wide bool) type {
|
|
` return { Selected := i8
|
|
` if (wide) Selected = i16
|
|
` yield Selected }
|
|
`}
|
|
`Box proc(wide bool) type {
|
|
` return struct { value Choose(wide) = { yield 42 } }
|
|
`}
|
|
`compute proc() i16 {
|
|
` return { value i16 := 40
|
|
` defer value = 0
|
|
` yield value + 2 }
|
|
`}
|
|
`main proc() i16 {
|
|
` value Box(true) :: {}
|
|
` constant :: $(compute())
|
|
` return { yield if (constant == value.value) constant else -1 }
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&bytes)
|
|
_ = try add_source(&session, root, "yielding.hon", &bytes, &diagnostic_store)
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for modules |module| {
|
|
outcome := try interpreter.run(mem.c_allocator, &module, &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
}
|
|
|
|
compound_updates_and_type_composition_recompile_without_retaining_rewrites test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
bytes := try owned_text(
|
|
`A :: enum { first }
|
|
`B :: enum { second }
|
|
`Errors :: A | B
|
|
`Box proc() type {
|
|
` counts [1]mut usize := [1]
|
|
` counts[0] <<= 1
|
|
` return struct { values [counts[0]]i16 }
|
|
`}
|
|
`compute proc() u8 {
|
|
` value u8 := 21
|
|
` value <<= 1
|
|
` return value
|
|
`}
|
|
`main proc() i16 {
|
|
` box Box() :: { values = [40, 2] }
|
|
` answer i16 := i16($(compute()))
|
|
` answer xor= box.values[0] + box.values[1]
|
|
` return answer + 42
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&bytes)
|
|
_ = try add_source(&session, root, "operators.hon", &bytes, &diagnostic_store)
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for modules |module| {
|
|
outcome := try interpreter.run(mem.c_allocator, &module, &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
}
|
|
|
|
computed_callbacks_recompile_without_retaining_interpreter_function_ids test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
dependency :: try add_package(&session)
|
|
bytes := try owned_text(
|
|
`lib :: import "../library"
|
|
`increment proc(value i16) i16 { return value + 100 }
|
|
`main proc() i16 {
|
|
` callback :: $(lib.choose())
|
|
` return callback(41)
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&bytes)
|
|
root_source :: try add_source(&session, root, "/callbacks/app/main.hon", &bytes, &diagnostic_store)
|
|
imported := try owned_text(
|
|
`Callback :: alias @proc(value i16) i16
|
|
`bias i16 :: 1
|
|
`@hide:file
|
|
`increment proc(value i16) i16 { return value + bias }
|
|
`choose proc() Callback { return increment }
|
|
,
|
|
)
|
|
defer arraylist.deinit(&imported)
|
|
_ = try add_source(&session, dependency, "/callbacks/library/callback.hon", &imported, &diagnostic_store)
|
|
try arraylist.append(&session.imports, Import{
|
|
node = declaration(&session, root_source, 0).node,
|
|
target = dependency,
|
|
})
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for modules |module| {
|
|
outcome := try interpreter.run(mem.c_allocator, &module, &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
}
|
|
|
|
computed_byte_slices_recompile_without_borrowing_evaluation_storage test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
dependency :: try add_package(&session)
|
|
bytes := try owned_text(
|
|
`lib :: import "../library"
|
|
`main proc() i16 {
|
|
` packet :: $(lib.make())
|
|
` if (packet.bytes.len != 4 or packet.suffix.len != 3) return -1
|
|
` if (packet.bytes[0] != 255 or packet.bytes[1] != 0) return -2
|
|
` if (packet.bytes[2] != 128 or packet.bytes[3] != 42) return -3
|
|
` if (packet.suffix[0] != 65 or packet.suffix[1] != 0) return -4
|
|
` if (packet.suffix[2] != 66 or packet.suffix.ptr[3] != 0) return -5
|
|
` if (packet.marked.len != 2 or packet.marked.ptr[2] != 255) return -6
|
|
` if (packet.marked[0] != 40 or packet.marked[1] != 2) return -7
|
|
` return 42
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&bytes)
|
|
root_source :: try add_source(&session, root, "/byte_slices/app/main.hon", &bytes, &diagnostic_store)
|
|
imported := try owned_text(
|
|
`Packet :: struct { bytes []u8, suffix [;0]u8, marked [;255]u8 }
|
|
`make proc() Packet {
|
|
` bytes [4]mut u8 := undefined
|
|
` bytes[0] = 255
|
|
` bytes[1] = 0
|
|
` bytes[2] = 128
|
|
` bytes[3] = 42
|
|
` marked [3]mut u8 := [40, 2, 255]
|
|
` return Packet { bytes = bytes[..], suffix = "xA\0B"[1..;0], marked = marked[..2;255] }
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&imported)
|
|
_ = try add_source(&session, dependency, "/byte_slices/library/bytes.hon", &imported, &diagnostic_store)
|
|
try arraylist.append(&session.imports, Import{
|
|
node = declaration(&session, root_source, 0).node,
|
|
target = dependency,
|
|
})
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for modules |module| {
|
|
outcome := try interpreter.run(mem.c_allocator, &module, &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
}
|
|
|
|
computed_nonbyte_slices_recompile_owned_private_elements_and_callbacks test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
dependency :: try add_package(&session)
|
|
bytes := try owned_text(
|
|
`lib :: import "../library"
|
|
`Code :: distinct i16
|
|
`Entry :: struct { value bool }
|
|
`increment proc(value Code) i16 { return i16(value) + 100 }
|
|
`main proc() i16 {
|
|
` entries :: $(lib.make())
|
|
` if (entries.len != 2 or entries[0].nested.len != 2) return -1
|
|
` if (entries[0].nested[0] != -300 or entries[0].nested[1] != 1024) return -2
|
|
` if (entries[1].nested.len != 1 or entries[1].nested[0] != 1024) return -3
|
|
` if (i16(entries[0].value) != 40 or i16(entries[1].value) != 41) return -4
|
|
` if (entries[1].run(entries[1].value) != 43) return -5
|
|
` return entries[0].run(entries[0].value)
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&bytes)
|
|
root_source :: try add_source(&session, root, "/nonbyte_slices/app/main.hon", &bytes, &diagnostic_store)
|
|
imported := try owned_text(
|
|
`@hide:file
|
|
`Code :: distinct i16
|
|
`@hide:file
|
|
`Callback :: alias @proc(value Code) i16
|
|
`@hide:file
|
|
`Entry :: struct { value Code, run Callback, nested []i16 }
|
|
`bias i16 :: 2
|
|
`@hide:file
|
|
`increment proc(value Code) i16 { return i16(value) + bias }
|
|
`make proc() []Entry {
|
|
` values [2]i16 :: [-300, 1024]
|
|
` entries [2]Entry :: [
|
|
` { value = 40, run = increment, nested = values[..] },
|
|
` { value = 41, run = increment, nested = values[1..] },
|
|
` ]
|
|
` return entries[..]
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&imported)
|
|
_ = try add_source(&session, dependency, "/nonbyte_slices/library/items.hon", &imported, &diagnostic_store)
|
|
try arraylist.append(&session.imports, Import{
|
|
node = declaration(&session, root_source, 0).node,
|
|
target = dependency,
|
|
})
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for modules |module| {
|
|
outcome := try interpreter.run(mem.c_allocator, &module, &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
}
|
|
|
|
computed_untagged_unions_recompile_without_borrowing_storage_bytes test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
dependency :: try add_package(&session)
|
|
bytes := try owned_text(
|
|
`lib :: import "../library"
|
|
`main proc() u64 {
|
|
` value := $(lib.make())
|
|
` saved :: value
|
|
` value.small = 0
|
|
` value.words[1] = 99
|
|
` if (saved.small != 9 or saved.bytes[1] != 255 or saved.bytes[7] != 255) return 0
|
|
` if (saved.bytes[17] != 255 or saved.bytes[23] != 255) return 0
|
|
` generated lib.Generated() :: {}
|
|
` if (generated.value.words[1] != 40 or generated.value.small != 9) return 0
|
|
` return saved.words[1] + saved.words[3]
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&bytes)
|
|
root_source :: try add_source(&session, root, "/union_bytes/app/main.hon", &bytes, &diagnostic_store)
|
|
imported := try owned_text(
|
|
`Pair :: struct { small u8, large u64 }
|
|
`Storage :: union { small u8, rows [2]Pair, words [4]mut u64, bytes [32]u8 }
|
|
`make proc() Storage {
|
|
` value := Storage { words = [maxval!(u64), 40, maxval!(u64), 2] }
|
|
` value.small = 9
|
|
` return value
|
|
`}
|
|
`Generated proc() type {
|
|
` return struct_type!(.auto, ["value"], [Storage], [make()])
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&imported)
|
|
_ = try add_source(&session, dependency, "/union_bytes/library/storage.hon", &imported, &diagnostic_store)
|
|
try arraylist.append(&session.imports, Import{
|
|
node = declaration(&session, root_source, 0).node,
|
|
target = dependency,
|
|
})
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for modules |module| {
|
|
outcome := try interpreter.run(mem.c_allocator, &module, &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
}
|
|
|
|
optional_type_metadata_recompiles_owned_private_nominal_payloads test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
dependency :: try add_package(&session)
|
|
bytes := try owned_text(
|
|
`lib :: import "../library"
|
|
`Child :: struct { value bool }
|
|
`main proc() i16 {
|
|
` if (lib.Box(lib.make()) != lib.Box(lib.make())) return -1
|
|
` if (lib.Selected() == Child) return -2
|
|
` value lib.Selected() :: { value = 42 }
|
|
` return value.value
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&bytes)
|
|
root_source :: try add_source(&session, root, "/optional_types/app/main.hon", &bytes, &diagnostic_store)
|
|
imported := try owned_text(
|
|
`@hide:file
|
|
`Child :: struct { value i16 }
|
|
`@hide:file
|
|
`Config :: struct { child ?type, count usize }
|
|
`make proc() ?Config { return { child = Child, count = 2 } }
|
|
`Box proc(input ?Config) type {
|
|
` info :: input?
|
|
` T :: info.child?
|
|
` return struct { values [info.count]T }
|
|
`}
|
|
`Selected proc() type {
|
|
` if make() |info| { return info.child? }
|
|
` return bool
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&imported)
|
|
_ = try add_source(&session, dependency, "/optional_types/library/types.hon", &imported, &diagnostic_store)
|
|
try arraylist.append(&session.imports, Import{
|
|
node = declaration(&session, root_source, 0).node,
|
|
target = dependency,
|
|
})
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for modules |module| {
|
|
outcome := try interpreter.run(mem.c_allocator, &module, &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
}
|
|
|
|
fallible_type_metadata_recompiles_owned_private_nominal_payloads test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
dependency :: try add_package(&session)
|
|
bytes := try owned_text(
|
|
`lib :: import "../library"
|
|
`Child :: struct { value bool }
|
|
`ErrorChild :: struct { value bool }
|
|
`main proc() i16 {
|
|
` if (lib.Box($(lib.make(true))) != lib.Box(lib.make(true))) return -1
|
|
` if (lib.Box($(lib.make(false))) != lib.Box(lib.make(false))) return -2
|
|
` Selected :: lib.Selected(true) catch bool
|
|
` Recovered :: lib.Recovered()
|
|
` if (Selected == Child or Recovered == ErrorChild) return -3
|
|
` selected Selected :: { value = 40 }
|
|
` recovered Recovered :: { value = 2 }
|
|
` snapshot lib.Snapshot($(lib.make(true))) :: {
|
|
` original = { values = [{ value = 19 }, { value = 21 }] },
|
|
` replacement = { values = [{ value = 2 }] },
|
|
` }
|
|
` if (snapshot.original.values[0].value + snapshot.original.values[1].value != 40) return -4
|
|
` if (snapshot.replacement.values[0].value != 2) return -5
|
|
` failed lib.Box($(lib.make(false))) :: { values = [{ value = 2 }] }
|
|
` if (failed.values[0].value != recovered.value) return -6
|
|
` return selected.value + recovered.value
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&bytes)
|
|
root_source :: try add_source(&session, root, "/fallible_types/app/main.hon", &bytes, &diagnostic_store)
|
|
imported := try owned_text(
|
|
`@hide:file
|
|
`Child :: struct { value i16 }
|
|
`@hide:file
|
|
`ErrorChild :: struct { value i16 }
|
|
`@hide:file
|
|
`Config :: struct { child type, count usize }
|
|
`@hide:file
|
|
`Failure :: struct { child type, count usize }
|
|
`make proc(success bool) Config ! Failure {
|
|
` if (success) return Config { child = Child, count = 2 }
|
|
` return Failure { child = ErrorChild, count = 1 }
|
|
`}
|
|
`Box proc(input Config ! Failure) type {
|
|
` info :: input catch |err| { return struct { values [err.count]err.child } }
|
|
` return struct { values [info.count]info.child }
|
|
`}
|
|
`Selected proc(success bool) type ! Failure {
|
|
` info :: try make(success)
|
|
` return info.child
|
|
`}
|
|
`Recovered proc() type {
|
|
` return Selected(false) catch |err| err.child
|
|
`}
|
|
`Snapshot proc(input Config ! Failure) type {
|
|
` changed := input
|
|
` saved :: changed
|
|
` changed = make(false)
|
|
` return struct { original Box(saved), replacement Box(changed) }
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&imported)
|
|
_ = try add_source(&session, dependency, "/fallible_types/library/types.hon", &imported, &diagnostic_store)
|
|
try arraylist.append(&session.imports, Import{
|
|
node = declaration(&session, root_source, 0).node,
|
|
target = dependency,
|
|
})
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for modules |module| {
|
|
outcome := try interpreter.run(mem.c_allocator, &module, &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
}
|
|
|
|
readonly_type_slices_recompile_owned_private_nominal_payloads test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
dependency :: try add_package(&session)
|
|
bytes := try owned_text(
|
|
`lib :: import "../library"
|
|
`Child :: struct { value bool }
|
|
`Storage proc() type {
|
|
` saved :: $(lib.make())
|
|
` if (lib.Box(saved) != lib.Box(lib.make())) return bool
|
|
` if (lib.Box(saved) != lib.Box(lib.literal())) return bool
|
|
` Selected :: lib.types()[0]
|
|
` if (Selected == Child or saved[0].child != Selected) return bool
|
|
` return lib.Box(saved)
|
|
`}
|
|
`main proc() i16 {
|
|
` value lib.types()[0] :: { value = 40 }
|
|
` if (lib.read(lib.make(), value) != 42) return -1
|
|
` box Storage() :: { values = [{ value = 19 }, { value = 21 }] }
|
|
` same lib.Box(lib.literal()) :: box
|
|
` return same.values[0].value + same.values[1].value + same.bias
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&bytes)
|
|
root_source :: try add_source(&session, root, "/readonly_type_slices/app/main.hon", &bytes, &diagnostic_store)
|
|
imported := try owned_text(
|
|
`@hide:file
|
|
`Child :: struct { value i16 }
|
|
`@hide:file
|
|
`Config :: struct { child type, count usize }
|
|
`types proc() []type { return [Child] }
|
|
`literal proc() []Config {
|
|
` return [{ child = Child, count = 2 }, { child = Child, count = 2 }]
|
|
`}
|
|
`make proc() []Config {
|
|
` rows [3]Config := [
|
|
` { child = Child, count = 99 },
|
|
` { child = Child, count = 2 },
|
|
` { child = Child, count = 2 },
|
|
` ]
|
|
` frozen :: rows
|
|
` saved :: frozen[1..][..2]
|
|
` rows = [
|
|
` { child = bool, count = 7 },
|
|
` { child = bool, count = 7 },
|
|
` { child = bool, count = 7 },
|
|
` ]
|
|
` return saved
|
|
`}
|
|
`Box proc(input []Config) type {
|
|
` return struct { values [input[0].count]input[0].child, bias i16 = i16(input[1].count) }
|
|
`}
|
|
`read proc($input []Config, value input[0].child) i16 {
|
|
` return value.value + i16(input[1].count)
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&imported)
|
|
_ = try add_source(&session, dependency, "/readonly_type_slices/library/types.hon", &imported, &diagnostic_store)
|
|
try arraylist.append(&session.imports, Import{
|
|
node = declaration(&session, root_source, 0).node,
|
|
target = dependency,
|
|
})
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for modules |module| {
|
|
outcome := try interpreter.run(mem.c_allocator, &module, &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
}
|
|
|
|
tagged_type_metadata_recompiles_owned_private_nominal_payloads test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
dependency :: try add_package(&session)
|
|
bytes := try owned_text(
|
|
`lib :: import "../library"
|
|
`Child :: struct { value bool }
|
|
`Storage proc() type {
|
|
` saved :: $(lib.make())
|
|
` if (lib.Box(saved) != lib.Box(lib.make())) return bool
|
|
` if (lib.Box(saved) != lib.Box(lib.literal())) return bool
|
|
` Selected :: saved.payload.children[0]?
|
|
` if (Selected == Child) return bool
|
|
` return lib.Snapshot(saved)
|
|
`}
|
|
`main proc() i16 {
|
|
` Selected :: lib.Selected(lib.make())
|
|
` value Selected :: { value = 40 }
|
|
` if (lib.read(lib.make(), value) != 42) return -4
|
|
` if (lib.score(lib.make(), 40) != 42) return -6
|
|
` if (lib.score_local(40) != 42) return -7
|
|
` snapshot Storage() :: {
|
|
` original = { values = [{ value = 19 }, { value = 21 }] },
|
|
` nested = { values = [true] },
|
|
` replacement = { values = [{ value = 2 }] },
|
|
` }
|
|
` if (!snapshot.nested.values[0]) return -5
|
|
` return (snapshot.original.values[0].value
|
|
` + snapshot.original.values[1].value + snapshot.replacement.values[0].value)
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&bytes)
|
|
root_source :: try add_source(&session, root, "/tagged_types/app/main.hon", &bytes, &diagnostic_store)
|
|
imported := try owned_text(
|
|
`@hide:file
|
|
`Child :: struct { value i16 }
|
|
`@hide:file
|
|
`Config :: struct { children [2]mut ?type, count usize }
|
|
`@hide:file
|
|
`Metadata :: union(enum) { payload Config, fallback type }
|
|
`literal proc() Metadata {
|
|
` return { payload = { children = [Child, null], count = 2 } }
|
|
`}
|
|
`make proc() Metadata {
|
|
` value Metadata := undefined
|
|
` value = Metadata { payload = { children = [bool, null], count = 1 } }
|
|
` value.payload.children[0] = Child
|
|
` value.payload.count = 2
|
|
` saved :: value
|
|
` value.payload.children[0] = bool
|
|
` value = Metadata { fallback = bool }
|
|
` return saved
|
|
`}
|
|
`Box proc(input Metadata) type {
|
|
` match input {
|
|
` .payload |info|: {
|
|
` T :: info.children[0]?
|
|
` return struct { values [info.count]T }
|
|
` },
|
|
` .fallback |ChildType|: return struct { values [1]ChildType },
|
|
` }
|
|
`}
|
|
`Snapshot proc(input Metadata) type {
|
|
` changed := input
|
|
` saved :: changed
|
|
` changed.payload.children[0] = bool
|
|
` changed.payload.count = 1
|
|
` nested :: changed
|
|
` changed = Metadata { fallback = Child }
|
|
` return struct { original Box(saved), nested Box(nested), replacement Box(changed) }
|
|
`}
|
|
`Selected proc(input Metadata) type { return input.payload.children[0]? }
|
|
`read proc($input Metadata, value Selected(input)) i16 {
|
|
` return value.value + i16(input.payload.count)
|
|
`}
|
|
`score proc(input Metadata, bias i16) i16 {
|
|
` saved :: input
|
|
` changed := input
|
|
` changed.payload.children[0] = bool
|
|
` if (saved.payload.children[0]? != Child) return -1
|
|
` return i16(saved.payload.count) + bias
|
|
`}
|
|
`score_local proc(bias i16) i16 {
|
|
` config := Config { children = [Child, null], count = 2 }
|
|
` saved :: config
|
|
` config.children[0] = bool
|
|
` if (saved.children[0]? != Child) return -1
|
|
` return i16(saved.count) + bias
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&imported)
|
|
_ = try add_source(&session, dependency, "/tagged_types/library/types.hon", &imported, &diagnostic_store)
|
|
try arraylist.append(&session.imports, Import{
|
|
node = declaration(&session, root_source, 0).node,
|
|
target = dependency,
|
|
})
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for modules |module| {
|
|
outcome := try interpreter.run(mem.c_allocator, &module, &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
}
|