mirror of
https://github.com/Nexoniarz/Finch.git
synced 2026-11-03 00:44:27 +00:00
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:
parent
a5ba4bc8f0
commit
609ceffe58
15 changed files with 576 additions and 18 deletions
|
|
@ -26,12 +26,10 @@ else
|
|||
fi
|
||||
|
||||
pass=0; failed=0; skipped=0
|
||||
for f in tests/run/*.fch; do
|
||||
# tests/run: what the C++ compiler also runs. tests/new: the language since then (enums, match, ...),
|
||||
# which only this compiler has.
|
||||
for f in tests/run/*.fch tests/new/*.fch; do
|
||||
grep -q "^fn main" "$f" || continue
|
||||
# the bootstrap compiler doesn't do C structs by value
|
||||
# (checked in the test and in the modules it imports)
|
||||
files="$f"
|
||||
for m in $(sed -n 's/^import \([a-z_]*\)$/\1/p' "$f"); do files="$files tests/run/$m.fch"; done
|
||||
input="${f%.fch}.in"
|
||||
[ -f "$input" ] || input=/dev/null
|
||||
if ! "$boot" build "$f" -o "$tmp/prog" > "$tmp/err" 2>&1; then
|
||||
|
|
@ -49,5 +47,18 @@ for f in tests/run/*.fch; do
|
|||
diff <(echo "$got") "${f%.fch}.out" | head -10
|
||||
fi
|
||||
done
|
||||
# programs that must be refused, and say why: the first line is "// expect: <text of the error>"
|
||||
for f in tests/new/fail/*.fch; do
|
||||
expect=$(head -1 "$f" | sed -n 's|^// expect: ||p')
|
||||
got=$("$boot" build "$f" -o "$tmp/refused" 2>&1)
|
||||
status=$?
|
||||
if [ $status -ne 0 ] && [[ "$got" == *"$expect"* ]]; then
|
||||
pass=$((pass + 1))
|
||||
else
|
||||
failed=$((failed + 1))
|
||||
echo "FAIL $f (wanted: $expect)"
|
||||
echo "$got" | head -3
|
||||
fi
|
||||
done
|
||||
echo "self-hosted compiler: $pass passed, $failed failed, $skipped skipped (features it doesn't have)"
|
||||
[ $failed -eq 0 ]
|
||||
|
|
|
|||
75
tests/new/enums.fch
Normal file
75
tests/new/enums.fch
Normal 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
14
tests/new/enums.out
Normal 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!
|
||||
6
tests/new/fail/enum_bad_number.fch
Normal file
6
tests/new/fail/enum_bad_number.fch
Normal 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))
|
||||
}
|
||||
6
tests/new/fail/enum_compare_order.fch
Normal file
6
tests/new/fail/enum_compare_order.fch
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
// expect: enums can only be compared with == and !=
|
||||
enum Color { Red, Green }
|
||||
|
||||
fn main() {
|
||||
print(Color.Red < Color.Green)
|
||||
}
|
||||
6
tests/new/fail/enum_no_variant.fch
Normal file
6
tests/new/fail/enum_no_variant.fch
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
// expect: the enum Color has no variant 'Blue'
|
||||
enum Color { Red, Green }
|
||||
|
||||
fn main() {
|
||||
print(Color.Blue)
|
||||
}
|
||||
8
tests/new/fail/match_arm_after_else.fch
Normal file
8
tests/new/fail/match_arm_after_else.fch
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
// expect: this arm can never be used
|
||||
fn main() {
|
||||
n := 3
|
||||
match n {
|
||||
else -> print("any")
|
||||
1 -> print("one")
|
||||
}
|
||||
}
|
||||
9
tests/new/fail/match_arms_differ.fch
Normal file
9
tests/new/fail/match_arms_differ.fch
Normal 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)
|
||||
}
|
||||
10
tests/new/fail/match_missing_variant.fch
Normal file
10
tests/new/fail/match_missing_variant.fch
Normal 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)
|
||||
}
|
||||
}
|
||||
8
tests/new/fail/match_needs_else.fch
Normal file
8
tests/new/fail/match_needs_else.fch
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
// expect: needs an 'else' arm
|
||||
fn main() {
|
||||
n := 3
|
||||
match n {
|
||||
1 -> print("one")
|
||||
2 -> print("two")
|
||||
}
|
||||
}
|
||||
11
tests/new/fail/match_not_a_variant.fch
Normal file
11
tests/new/fail/match_not_a_variant.fch
Normal 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)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue