123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 | enum Foo(Zero, One{x:Int}, Two{x:Int, y:Int}, Three{x:Int, y:Text, z:Bool}, Four{x,y,z,w:Int}, Last{t:Text})
enum OnlyTags(A, B, C, D)
func choose_text(f:Foo->Text)
>> f
match f
case Zero
return "Zero"
case One{one}
return "One: $one"
case Two{x, y}
return "Two: x=$x, y=$y"
case Three{three}
return "Three: $three"
case Four
return "Four"
else
return "else: $f"
func enum_arg_function(thing:enum(Zero, One{x:Int}, Two{x,y:Int}))
>> thing
func enum_return_function(i:Int -> enum(Zero, One, Many))
if i == 0
return Zero
else if i == 1
return One
else
return Many
struct EnumFields{x:enum(A, B, C)}
test "enum equality and comparison"
>> Foo.Zero
>> Foo.One{123}
>> Foo.Two{123, 456}
>> Foo.One{10}
assert Foo.Zero == Foo.Zero
assert Foo.One{123} == Foo.One{123}
assert Foo.Two{123, 456} == Foo.Two{x=123, y=456}
assert Foo.One{10} == Foo.One{10}
assert Foo.One{10} != Foo.Zero
assert Foo.One{10} != Foo.One{-1}
assert Foo.One{10} < Foo.Two{1, 2}
test "enum values as table keys"
>> x := Foo.One{123}
>> t := {x: yes}
>> t.has(x)
>> t.has(Foo.Zero)
assert t.has(x)
assert not t.has(Foo.Zero)
test "pattern matching with match"
>> choose_text(Foo.Zero)
>> choose_text(Foo.One{123})
>> choose_text(Foo.Two{123, 456})
>> choose_text(Foo.Four{1,2,3,4})
assert choose_text(Foo.Zero) == "Zero"
assert choose_text(Foo.One{123}) == "One: 123"
assert choose_text(Foo.Two{123, 456}) == "Two: x=123, y=456"
assert choose_text(Foo.Three{123, "hi", yes}) == 'Three: Three{x=123, y="hi", z=yes}'
assert choose_text(Foo.Four{1,2,3,4}) == "Four"
assert choose_text(Foo.Last{"XX"}) == 'else: Last{"XX"}'
test "repeat match over a list"
>> i := 1
>> cases := [Foo.One{1}, Foo.One{2}, Foo.Zero]
repeat match cases[i]!
case One{x}
>> x
i += 1
else break
test "match in a comprehension"
assert [
(
match x
case One{y}, Two{y,_}
"Small $y"
case Zero
"Zero"
else
"Other"
) for x in [Foo.Zero, Foo.One{1}, Foo.Two{2,2}, Foo.Three{3,"",no}]
] == ["Zero", "Small 1", "Small 2", "Other"]
test "match as an expression"
>> cases := [Foo.One{1}, Foo.One{2}, Foo.Zero]
>> expr := match cases[1]!
case One{y}
y + 1
else
-1
>> expr
assert expr == 2
test "inline enum argument type"
>> enum_arg_function(Zero)
>> enum_arg_function(Two{2,3})
test "inline enum local variable"
e : enum(One, Two) = One
e = Two
match e
case One
say("one")
case Two
say("two")
test "inline enum return type"
>> enum_return_function(0)
>> enum_return_function(1)
>> enum_return_function(2)
assert enum_return_function(0) == Zero
assert enum_return_function(1) == One
assert enum_return_function(2) == Many
test "struct with enum field"
>> EnumFields{A}
>> EnumFields{x=A}
assert EnumFields{A} == EnumFields{x=A}
test "tag accessors on a tag-only enum"
>> e := OnlyTags.A
>> e.A
>> e.B
assert e.A == OnlyTags.A.A
assert e.B == none
test "tag accessors"
>> e := Foo.Zero
>> e.Zero
>> e.One
>> e.Two
assert e.Zero == Foo.Zero.Zero
assert e.One == none
assert e.Two == none
>> ep := @Foo.Zero
>> ep.Zero
assert ep.Zero == Foo.Zero.Zero
assert ep.One == none
assert ep.Two == none
test "tag accessor extraction"
>> e := Foo.Two{123, 456}
>> e.Zero
>> e.One
>> e.Two
assert e.Zero == none
assert e.One == none
assert e.Two != none
>> ep := Foo.Two{123, 456}
assert ep.Zero == none
assert ep.One == none
assert ep.Two != none
>> two := e.Two!
match e
case Two{x,y}
assert two.x == x
assert two.y == y
else fail("Unreachable")
test "referencing a nonexistent enum variant is rejected"
f := Foo.Nonexistent
fails_compile "I couldn't find the field 'Nonexistent' on this type"
test "constructing an enum variant with the wrong argument type is rejected"
f := Foo.One{"not an int"}
fails_compile "This enum variant's fields don't match this value."
test "constructing an enum variant with parentheses is rejected"
f := Foo.One(123)
fails_compile "Enum variants are built with curly braces, not parentheses"
test "a variant with no fields is rejected with curly braces"
f := Foo.Zero{}
fails_compile "doesn't have any fields, so write it without curly braces"
enum Wrapper(Wrapped{n:Int})
func Wrapped(x:Int -> Wrapper)
return Wrapper.Wrapped{x * 2}
test "a plain function sharing a tag's name and return type is still callable with parens"
>> Wrapped(5)
assert Wrapped(5) == Wrapper.Wrapped{10}
enum Private(Secret{_x, y:Int})
test "building a variant with underscore-prefixed fields as positional arguments is allowed"
>> Private.Secret{123, 5}
test "building a variant with underscore-prefixed fields as keyword arguments is allowed"
>> Private.Secret{_x=123, y=5}
enum MultiField(
Multi{
x:Int
y:Int
}
None
)
test "enum variant fields can be separated by newlines instead of commas"
>> MultiField.Multi{1, 2}
assert MultiField.Multi{1, 2} == MultiField.Multi{x=1, y=2}
|