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
|
|
@ -173,6 +173,8 @@ fn parseProgram(ptr[Parser] p) -> ast.Program {
|
|||
prog.links.push(expect(p, "string", "a library or C file name, like link \"glfw\"").text)
|
||||
} else if at(p, "struct") {
|
||||
prog.structs.push(parseStruct(p))
|
||||
} else if at(p, "enum") {
|
||||
prog.enums.push(parseEnum(p))
|
||||
} else {
|
||||
prog.fns.push(parseFn(p))
|
||||
}
|
||||
|
|
@ -180,6 +182,86 @@ fn parseProgram(ptr[Parser] p) -> ast.Program {
|
|||
return prog
|
||||
}
|
||||
|
||||
// enum Color { Red, Green, Blue } enum Status { Ok = 200, NotFound = 404 }
|
||||
// The variants are numbered from 0 (or from the last number given) and are written Color.Red.
|
||||
fn parseEnum(ptr[Parser] p) -> ast.Node {
|
||||
e := node(p, "enum")
|
||||
expect(p, "enum", "'enum'")
|
||||
e.name = expect(p, "ident", "an enum name").text
|
||||
expect(p, "{", "'{'")
|
||||
while !at(p, "}") {
|
||||
if at(p, "eof") {
|
||||
fail(p, cur(p), "an enum is never closed (missing '}')")
|
||||
}
|
||||
v := node(p, "variant")
|
||||
v.name = expect(p, "ident", "a variant name, like Red").text
|
||||
if accept(p, "=") {
|
||||
sign := ""
|
||||
if accept(p, "-") {
|
||||
sign = "-"
|
||||
}
|
||||
v.text = sign + expect(p, "int", "a whole number, like Ok = 200").text
|
||||
}
|
||||
e.kids.push(v)
|
||||
if !accept(p, ",") {
|
||||
endOfStatement(p)
|
||||
}
|
||||
}
|
||||
next(p)
|
||||
if e.kids.len == 0 {
|
||||
fail(p, cur(p), "the enum " + e.name + " has no variants")
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
// match value { A, B -> ... C -> ... else -> ... }
|
||||
// As a statement the arms are statements or { blocks }; as an expression they are expressions.
|
||||
fn parseMatch(ptr[Parser] p, bool asExpr) -> ast.Node {
|
||||
m := node(p, "match")
|
||||
m.flag = asExpr
|
||||
expect(p, "match", "'match'")
|
||||
m.kids.push(parseExpr(p))
|
||||
expect(p, "{", "'{'")
|
||||
saved := p.depth
|
||||
p.depth = 0
|
||||
while !at(p, "}") {
|
||||
if at(p, "eof") {
|
||||
fail(p, cur(p), "a match is never closed (missing '}')")
|
||||
}
|
||||
arm := node(p, "arm")
|
||||
pats := node(p, "patterns")
|
||||
if accept(p, "else") {
|
||||
arm.flag = true
|
||||
} else {
|
||||
while true {
|
||||
pats.kids.push(parseExpr(p))
|
||||
if !accept(p, ",") {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
arm.kids.push(pats)
|
||||
expect(p, "->", "'->' after the value to match, like Red -> print(\"red\")")
|
||||
if at(p, "{") && !asExpr {
|
||||
arm.kids.push(parseBlock(p))
|
||||
} else if asExpr {
|
||||
arm.kids.push(parseExpr(p))
|
||||
} else {
|
||||
arm.kids.push(parseStatement(p))
|
||||
}
|
||||
m.kids.push(arm)
|
||||
if !accept(p, ",") {
|
||||
endOfStatement(p)
|
||||
}
|
||||
}
|
||||
p.depth = saved
|
||||
next(p)
|
||||
if m.kids.len == 1 {
|
||||
fail(p, cur(p), "a match needs at least one arm")
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
fn parseStruct(ptr[Parser] p) -> ast.Node {
|
||||
s := node(p, "struct")
|
||||
expect(p, "struct", "'struct'")
|
||||
|
|
@ -293,6 +375,9 @@ fn parseStatement(ptr[Parser] p) -> ast.Node {
|
|||
s.kids.push(parseBlock(p))
|
||||
return s
|
||||
}
|
||||
if k == "match" {
|
||||
return parseMatch(p, false)
|
||||
}
|
||||
if k == "return" {
|
||||
s := node(p, "return")
|
||||
next(p)
|
||||
|
|
@ -532,6 +617,9 @@ fn parsePrimary(ptr[Parser] p) -> ast.Node {
|
|||
expect(p, ")", "')'")
|
||||
return inner
|
||||
}
|
||||
if k == "match" {
|
||||
return parseMatch(p, true)
|
||||
}
|
||||
if k == "[" {
|
||||
next(p)
|
||||
e.kind = "array"
|
||||
|
|
|
|||
Loading…
Reference in a new issue