91 lines
2.4 KiB
Go
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
|
|
}
|