llm
Download
305 lines 7.4 KiBTomoModified 2026-08-30 raw
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305

struct Struct{x:Int, y:Text}
    func maybe(should_i:Bool->Struct?)
        if should_i
            return Struct{123, "hello"}
        else
            return none

enum Enum(X, Y{y:Int})
    func maybe(should_i:Bool->Enum?)
        if should_i
            return Enum.Y{123}
        else
            return none

func maybe_int(should_i:Bool->Int?)
    if should_i
        return 123
    else
        return none

func maybe_int64(should_i:Bool->Int64?)
    if should_i
        return Int64(123)
    else
        return none

func maybe_list(should_i:Bool->[Int]?)
    if should_i
        return [10, 20, 30]
    else
        return none

func maybe_bool(should_i:Bool->Bool?)
    if should_i
        return no
    else
        return none

func maybe_text(should_i:Bool->Text?)
    if should_i
        return "Hello"
    else
        return none

func maybe_num(should_i:Bool->Float64?)
    if should_i
        return 12.3
    else
        return none

func maybe_lambda(should_i:Bool-> func()?)
    if should_i
        return func() say("hi!")
    else
        return none

func maybe_c_string(should_i:Bool->CString?)
    if should_i
        return "hi".as_c_string()
    else
        return none

func maybe_path(should_i:Bool->Path?)
    if should_i
        return ./foo
    else
        return none

test "basic optional values"
    >> optional : Int? = 5
    >> optional
    assert optional == 5

    assert (
        if no
            x : Int? = none
            x
        else
            5
    ) == 5

    >> (optional or -1)
    assert (optional or -1) == 5
    assert (optional or fail("Non-none is falsey")) == 5
    assert (optional or exit("Non-none is falsey")) == 5
    >> none_int : Int? = none
    >> none_int
    assert none_int or -1 == -1

test "optional Ints"
    >> yep := maybe_int(yes)
    assert yep == 123
    >> nope := maybe_int(no)
    assert nope == none
    if yep
        assert yep == 123
    else fail("Falsey: $yep")
    if nope
        fail("Truthy: $nope")

test "optional Int64s"
    >> yep := maybe_int64(yes)
    assert yep == Int64(123)
    >> nope := maybe_int64(no)
    assert nope == none
    if yep
        assert yep == Int64(123)
    if nope
        fail("Truthy: $nope")

test "optional Lists"
    >> yep := maybe_list(yes)
    assert yep == [10, 20, 30]
    >> nope := maybe_list(no)
    assert nope == none
    if yep
        assert yep == [10, 20, 30]
    else fail("Falsey: $yep")
    if nope
        fail("Truthy: $nope")

test "optional Bools"
    >> yep := maybe_bool(yes)
    assert yep == no
    >> nope := maybe_bool(no)
    assert nope == none

test "Can't coerce optional booleans to booleans"
    yep := maybe_bool(yes)
    if yep
        assert yep == no
fails_compile "use an explicit `yep != none` check"

test "optional Text"
    >> yep := maybe_text(yes)
    assert yep == "Hello"
    >> nope := maybe_text(no)
    assert nope == none
    if yep
        assert yep == "Hello"
    else fail("Falsey: $yep")
    if nope
        fail("Truthy: $nope")

test "optional Nums"
    >> yep := maybe_num(yes)
    assert yep == 12.3
    >> nope := maybe_num(no)
    assert nope == none
    if yep
        assert yep == 12.3
    if nope
        fail("Truthy: $nope")

test "optional Lambdas"
    >> nope := maybe_lambda(no)
    >> nope
    assert nope == none
    if nope
        fail("Truthy: $nope")

test "optional Structs"
    >> yep := Struct.maybe(yes)
    assert yep == Struct{x=123, y="hello"}
    >> nope := Struct.maybe(no)
    assert nope == none
    if yep
        assert yep == Struct{x=123, y="hello"}
    if nope
        fail("Truthy: $nope")

test "optional Enums"
    >> yep := Enum.maybe(yes)
    assert yep == Enum.Y{123}
    >> nope := Enum.maybe(no)
    assert nope == none
    if yep
        assert yep == Enum.Y{123}
    if nope
        fail("Truthy: $nope")

test "optional C Strings"
    >> yep := maybe_c_string(yes)
    assert yep == CString("hi")
    >> nope := maybe_c_string(no)
    assert nope == none
    if yep
        assert yep == CString("hi")
    if nope
        fail("Truthy: $nope")

test "optional Paths"
    >> yep := maybe_path(yes)
    assert yep == ./foo
    >> nope := maybe_path(no)
    assert nope == none
    if yep
        assert yep == ./foo
    if nope
        fail("Truthy: $nope")

test "if-binding, force-unwrap, comparisons and hashing"
    >> optional : Int? = 5

    if yep := maybe_int(yes)
        >> yep
        assert yep == 123
    else fail("Unreachable")

    >> maybe_int(yes)!
    assert maybe_int(yes)! == 123

    # Test comparisons, hashing, equality:
    assert none != optional
    assert optional == 5
    >> nones : {Int?:Bool} = {none: yes, none: yes}
    >> nones.keys
    assert nones.keys == [none]
    >> [5, none, none, 6].sorted()
    assert [5, none, none, 6].sorted() == [none, none, 5, 6]

test "if-let binding uses value when present"
    >> optional : Int? = 5
    assert (if var := optional then var else 0) == 5

test "if-let binding falls through on none"
    assert (if var : Int? = none then var else 0) == 0

test "printing a present optional in if/else"
    opt : Int? = 5
    if opt
        >> opt
    else
        >> opt

test "printing a none optional in if/else"
    opt : Int? = none
    if opt
        >> opt
    else
        >> opt

test "'or' fallbacks can be untyped literals"
    # The fallback takes the optional's own type, so a bare literal works for
    # any of them, not just the bignum `Int`, whose type a literal already
    # has on its own.
    none_i64 : Int64? = none
    none_byte : Byte? = none
    none_f64 : Float64? = none
    none_f32 : Float32? = none
    none_num : Num? = none
    >> none_i64 or 0
    assert (none_i64 or 0) == Int64(0)
    assert (none_byte or 3) == Byte(3)
    assert (none_f64 or 0.0) == Float64(0)
    assert (none_f64 or 1.5) == Float64(1.5)
    assert (none_f32 or 1.5) == Float32(1.5)
    assert (none_num or 1./3.) == 1./3.
    # A present value still wins, and still comes out at that type:
    some_f64 : Float64? = 2.5
    >> kept : Float64 = some_f64 or 0.0
    assert kept == 2.5

test "negation and 'or' with optionals"
    >> optional : Int? = 5
    >> not optional
    assert (not optional) == no
    >> nah : Int? = none
    >> not nah
    assert (not nah) == yes
    assert [none, Struct{5,"A"}, Struct{6,"B"}, Struct{7,"C"}] == [none, Struct{x=5, y="A"}, Struct{x=6, y="B"}, Struct{x=7, y="C"}]
    if optional or no
        say("Binary op 'or' works with optionals")
    else
        fail("Failed to do binary op 'or' on optional")

test "force-unwrapping a none value panics"
    x : Int? = none
    _ := x!
fails "This was expected to be a value, but it's `none`"

test "dereferencing a maybe-none pointer is rejected"
    p : @Int? = none
    _ := p[]
fails_compile "Only pointers can use the '[]' operator to dereference the entire value."

test "reading a field through an optional is rejected"
    s : Struct? = Struct{5, "A"}
    _ := s.x
fails_compile "This value is optional (Struct?), so it might be none and I can't read its 'x' field"

test "a misspelled field on an optional still gets a suggestion"
    xs : [Int]? = [10, 20]
    n := xs.lenth
fails_compile "Did you mean 'length'?"

# `x or y` shares the `Or` AST node with bitwise-or, so it used to be mistaken
# for arithmetic whose type could be pushed into its operands:
test "an 'or' fallback can be used in arithmetic"
    n : Int? = 5
    assert (n or 0) + 1 == 6
    missing : Int? = none
    assert (missing or 0) + 1 == 1
    assert 2 * (n or 0) == 10