fspl/parser/parser.go
2024-02-06 02:55:39 -05:00

91 lines
2.4 KiB
Go

package parser
import "io"
import "fmt"
import "git.tebibyte.media/sashakoshka/fspl/lexer"
import "git.tebibyte.media/sashakoshka/fspl/errors"
// Parser parses tokens from a lexer into syntax entities, which it places into
// a tree.
type Parser struct {
token lexer.Token
lexer lexer.Lexer
tree *Tree
}
// NewParser creates a new parser that parses the given file.
func NewParser (name string, file io.Reader) (*Parser, error) {
lx, err := lexer.NewLexer(name, file)
if err != nil { return nil, err }
return &Parser {
lexer: lx,
}, nil
}
// ParseInto parses the parser's file into the given syntax tree.
func (this *Parser) ParseInto (tree *Tree) error {
this.tree = tree
err := this.parse()
if err == io.EOF { err = nil }
return err
}
// expect gets the next token if it matches a list of token kind(s), else it
// returns an error describing what it expected.
func (this *Parser) expect (allowed ...lexer.TokenKind) (lexer.Token, error) {
token, err := this.next()
if err != nil { return lexer.Token { }, err }
if !token.Is(allowed...) {
message := "expected"
for index, token := range allowed {
if index > 0 && len(allowed) > 2 {
message += ", "
}
if index == len(allowed) - 1 {
message += " or "
}
message += fmt.Sprintf(" %v", token)
}
return lexer.Token { }, errors.Errorf(token.Position, message)
}
return token, nil
}
// expectDesc is like expect, but the expected entitie(s) are described
// manually. This can be helpful when a large syntactical entity is expected and
// the first token(s) of it offer insufficient information.
func (this *Parser) expectDesc (description string, allowed ...lexer.TokenKind) (lexer.Token, error) {
token, err := this.next()
if err != nil { return lexer.Token { }, err }
if !token.Is(allowed...) {
return lexer.Token { }, errors.Errorf(token.Position, "expected %s", description)
}
return token, nil
}
func (this *Parser) next () (lexer.Token, error) {
token, err := this.lexer.Next()
if err != nil { return token, err }
this.token = token
return token, nil
}
func appendr[ELEMENT any] (item ELEMENT, array []ELEMENT) []ELEMENT {
return append([]ELEMENT { item }, array...)
}
func (this *Parser) parse () error {
for {
token, err := this.expectDesc (
descriptionTopLevel,
startTokensTopLevel...)
if err != nil { return err }
if token.EOF() { return nil }
err = this.parseTopLevel()
if err != nil { return err }
}
return nil
}