enums and match (in the compiler written in Finch)

enum Color { Red, Green, Blue }   enum Status { Ok = 200, NotFound = 404 }

Color.Red, Color(n) (checked), int(c), == and != only, printed by name, usable as
map keys and struct fields, with methods (fn Color.next()).

match value { Red, Green -> ... Blue -> ... else -> ... } as a statement, or as an
expression that gives a value. Works on enums, whole numbers, chars, text and bools;
a match on an enum has to handle every variant or end with else, and says which are
missing. A bare variant name (Red) is enough inside a match on an enum.

Only the self-hosted compiler has them; tests/new holds their tests, tests/run stays what
the C++ compiler also runs. boot.sh: 31 passed.
This commit is contained in:
Nexoniarz 2026-10-25 20:49:04 +01:00
commit 609ceffe58
15 changed files with 576 additions and 18 deletions

75
tests/new/enums.fch Normal file
View file

@ -0,0 +1,75 @@
enum Color { Red, Green, Blue }
enum Status { Ok = 200, NotFound = 404, Teapot = 418 }
struct Pixel {
Color color
int x
}
fn Color.warm() -> bool {
return self == Color.Red
}
fn Color.next() -> Color {
if self == Color.Red {
return Color.Green
}
if self == Color.Green {
return Color.Blue
}
return Color.Red
}
fn describe(Color c) -> str {
return match c {
Red -> "red"
Green -> "green"
Blue -> "blue"
}
}
fn code(Status s) -> str {
match s {
Status.Ok -> return "fine"
Status.NotFound, Status.Teapot -> return "odd"
}
}
fn main() {
c := Color.Green
print(c, Color.Blue, int(Color.Blue), int(Status.Teapot))
print(c == Color.Green, c != Color.Green)
print(describe(Color.Red), describe(c.next()), c.warm(), Color.Red.warm())
print(code(Status.Ok), code(Status.NotFound))
p := Pixel(color: Color.Blue, x: 3)
print(p)
[]Color all = [Color.Red, Color.Blue]
print(all, all.len)
for col in all {
match col {
Color.Red -> print("a red one")
else -> print("something else")
}
}
s := Status(404)
print(s, Status(200))
n := 5
kind := match n {
1, 2, 3 -> "small"
4, 5 -> "medium"
else -> "large"
}
print(kind)
word := "two"
match word {
"one" -> print(1)
"two" -> {
print(2)
print("two!")
}
else -> print("many")
}
counts := [Color.Red: 2, Color.Blue: 5]
print(counts[Color.Blue], counts)
print(str(Color.Green) + "!")
}

14
tests/new/enums.out Normal file
View file

@ -0,0 +1,14 @@
Green Blue 2 418
true false
red blue false true
fine odd
Pixel(color: Blue, x: 3)
[Red, Blue] 2
a red one
something else
NotFound Ok
medium
2
two!
5 {Red: 2, Blue: 5}
Green!

View file

@ -0,0 +1,6 @@
// expect: 7 is not the number of any variant of Color
enum Color { Red, Green }
fn main() {
print(Color(7))
}

View file

@ -0,0 +1,6 @@
// expect: enums can only be compared with == and !=
enum Color { Red, Green }
fn main() {
print(Color.Red < Color.Green)
}

View file

@ -0,0 +1,6 @@
// expect: the enum Color has no variant 'Blue'
enum Color { Red, Green }
fn main() {
print(Color.Blue)
}

View file

@ -0,0 +1,8 @@
// expect: this arm can never be used
fn main() {
n := 3
match n {
else -> print("any")
1 -> print("one")
}
}

View file

@ -0,0 +1,9 @@
// expect: the arms of a match have to give the same type
fn main() {
n := 3
x := match n {
1 -> "one"
else -> 2
}
print(x)
}

View file

@ -0,0 +1,10 @@
// expect: doesn't handle Blue
enum Color { Red, Green, Blue }
fn main() {
c := Color.Red
match c {
Red -> print(1)
Green -> print(2)
}
}

View file

@ -0,0 +1,8 @@
// expect: needs an 'else' arm
fn main() {
n := 3
match n {
1 -> print("one")
2 -> print("two")
}
}

View file

@ -0,0 +1,11 @@
// expect: 'Purple' is not a variant of Color
enum Color { Red, Green }
fn main() {
c := Color.Red
match c {
Red -> print(1)
Purple -> print(2)
else -> print(3)
}
}