Rework parser structure
This commit is contained in:
parent
f8ed70336d
commit
f07754d79a
3
main.go
3
main.go
@ -23,7 +23,8 @@ func main() {
|
|||||||
|
|
||||||
log.Printf("Tokens:\n%+#v\n\n", tokens)
|
log.Printf("Tokens:\n%+#v\n\n", tokens)
|
||||||
|
|
||||||
parsed, err := parser(tokens)
|
parser := Parser{tokens}
|
||||||
|
parsed, err := parser.parseFile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
170
parser.go
170
parser.go
@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"log"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@ -129,88 +130,100 @@ type ParsedFile struct {
|
|||||||
Functions []ParsedFunction
|
Functions []ParsedFunction
|
||||||
}
|
}
|
||||||
|
|
||||||
func expectSeparator(tokens []LexToken, separators ...Separator) (Separator, []LexToken, error) {
|
type Parser struct {
|
||||||
|
tokens []LexToken
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) peekToken() *LexToken {
|
||||||
|
if len(p.tokens) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &p.tokens[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) nextToken() *LexToken {
|
||||||
|
if len(p.tokens) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
token := p.tokens[0]
|
||||||
|
p.tokens = p.tokens[1:]
|
||||||
|
return &token
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) expectSeparator(separators ...Separator) (Separator, error) {
|
||||||
var separatorNames []string
|
var separatorNames []string
|
||||||
for _, sep := range separators {
|
for _, sep := range separators {
|
||||||
separatorNames = append(separatorNames, string(Separators[sep]))
|
separatorNames = append(separatorNames, string(Separators[sep]))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(tokens) == 0 {
|
separator := p.nextToken()
|
||||||
return InvalidValue, nil, errors.New("expected one of " + strings.Join(separatorNames, " "))
|
if separator == nil || separator.Type != Type_Separator || !slices.Contains(separators, separator.Value.(Separator)) {
|
||||||
|
return InvalidValue, errors.New("expected one of " + strings.Join(separatorNames, " "))
|
||||||
}
|
}
|
||||||
|
|
||||||
separator := tokens[0]
|
return separator.Value.(Separator), nil
|
||||||
if separator.Type != Type_Separator || !slices.Contains(separators, separator.Value.(Separator)) {
|
|
||||||
return InvalidValue, nil, errors.New("expected one of " + strings.Join(separatorNames, " "))
|
|
||||||
}
|
|
||||||
|
|
||||||
return separator.Value.(Separator), tokens[1:], nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func expectIdentifier(tokens []LexToken) (string, []LexToken, error) {
|
func (p *Parser) expectIdentifier() (string, error) {
|
||||||
if len(tokens) == 0 {
|
identifier := p.nextToken()
|
||||||
return "", nil, errors.New("expected identifier")
|
if identifier == nil || identifier.Type != Type_Separator && identifier.Type != Type_Identifier {
|
||||||
|
return "", errors.New("expected identifier")
|
||||||
}
|
}
|
||||||
|
|
||||||
token := tokens[0]
|
return identifier.Value.(string), nil
|
||||||
if token.Type != Type_Separator && token.Type != Type_Identifier {
|
|
||||||
return "", nil, errors.New("expected identifier")
|
|
||||||
}
|
|
||||||
|
|
||||||
return token.Value.(string), tokens[1:], nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseImport(tokens []LexToken) (*Import, []LexToken, error) {
|
func (p *Parser) expectImport() (*Import, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if len(tokens) < 3 {
|
importToken := p.nextToken()
|
||||||
return nil, nil, errors.New("incomplete import")
|
if importToken == nil || importToken.Type != Type_Keyword || importToken.Value.(Keyword) != Keyword_Import {
|
||||||
|
return nil, errors.New("expected import")
|
||||||
}
|
}
|
||||||
|
|
||||||
// tokens[0] == import keyword
|
identifier := p.nextToken()
|
||||||
|
if identifier == nil || identifier.Type != Type_Identifier {
|
||||||
identifier := tokens[1]
|
return nil, errors.New("expected identifier")
|
||||||
if identifier.Type != Type_Identifier {
|
|
||||||
return nil, nil, errors.New("expected identifier")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, tokens, err = expectSeparator(tokens[2:], Separator_Semicolon)
|
_, err = p.expectSeparator(Separator_Semicolon)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Import{Import: identifier.Value.(string)}, tokens, nil
|
return &Import{Import: identifier.Value.(string)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseType(tokens []LexToken) (*Type, []LexToken, error) {
|
func (p *Parser) expectType() (*Type, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if len(tokens) == 0 {
|
tok := p.nextToken()
|
||||||
return nil, nil, errors.New("expected type")
|
if tok == nil {
|
||||||
|
return nil, errors.New("expected type")
|
||||||
}
|
}
|
||||||
|
|
||||||
tok := tokens[0]
|
|
||||||
if tok.Type == Type_Keyword && tok.Value.(Keyword) == Keyword_Void {
|
if tok.Type == Type_Keyword && tok.Value.(Keyword) == Keyword_Void {
|
||||||
return &Type{Type: Type_Void, Value: nil}, tokens[1:], nil
|
return &Type{Type: Type_Void, Value: nil}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if tok.Type == Type_Separator && tok.Value.(Separator) == Separator_OpenParen {
|
if tok.Type == Type_Separator && tok.Value.(Separator) == Separator_OpenParen {
|
||||||
// Tuple type
|
// Tuple type
|
||||||
var types []Type
|
var types []Type
|
||||||
tokens = tokens[1:]
|
|
||||||
for {
|
for {
|
||||||
var parsedType *Type
|
var parsedType *Type
|
||||||
parsedType, tokens, err = parseType(tokens)
|
parsedType, err = p.expectType()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
types = append(types, *parsedType)
|
types = append(types, *parsedType)
|
||||||
|
|
||||||
var sep Separator
|
var sep Separator
|
||||||
sep, tokens, err = expectSeparator(tokens, Separator_Comma, Separator_CloseParen)
|
sep, err = p.expectSeparator(Separator_Comma, Separator_CloseParen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if sep == Separator_CloseParen {
|
if sep == Separator_CloseParen {
|
||||||
@ -219,20 +232,20 @@ func parseType(tokens []LexToken) (*Type, []LexToken, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(types) == 0 {
|
if len(types) == 0 {
|
||||||
return nil, nil, errors.New("empty tuple")
|
return nil, errors.New("empty tuple")
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Type{Type: Type_Tuple, Value: TupleType{Types: types}}, tokens, nil
|
return &Type{Type: Type_Tuple, Value: TupleType{Types: types}}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if tok.Type == Type_Identifier {
|
if tok.Type == Type_Identifier {
|
||||||
return &Type{Type: Type_Named, Value: tok.Value}, tokens[1:], nil
|
return &Type{Type: Type_Named, Value: tok.Value}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil, errors.New("expected type")
|
return nil, errors.New("expected type")
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseFunction(tokens []LexToken) (*ParsedFunction, []LexToken, error) {
|
func (p *Parser) expectFunction() (*ParsedFunction, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
var name string
|
var name string
|
||||||
@ -240,79 +253,86 @@ func parseFunction(tokens []LexToken) (*ParsedFunction, []LexToken, error) {
|
|||||||
var returnType *Type
|
var returnType *Type
|
||||||
var body Block
|
var body Block
|
||||||
|
|
||||||
returnType, tokens, err = parseType(tokens)
|
returnType, err = p.expectType()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(tokens) < 2 {
|
name, err = p.expectIdentifier()
|
||||||
return nil, nil, errors.New("incomplete function declaration")
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
name, tokens, err = expectIdentifier(tokens)
|
_, err = p.expectSeparator(Separator_OpenParen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
|
||||||
|
|
||||||
_, tokens, err = expectSeparator(tokens, Separator_OpenParen)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if len(tokens) == 0 {
|
token := p.peekToken()
|
||||||
return nil, nil, errors.New("incomplete function declaration")
|
if token == nil {
|
||||||
|
return nil, errors.New("incomplete function declaration")
|
||||||
}
|
}
|
||||||
|
|
||||||
token := tokens[0]
|
|
||||||
if token.Type == Type_Separator && token.Value.(Separator) == Separator_CloseParen {
|
if token.Type == Type_Separator && token.Value.(Separator) == Separator_CloseParen {
|
||||||
tokens = tokens[1:]
|
p.nextToken()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(parameters) > 0 {
|
if len(parameters) > 0 {
|
||||||
if token.Type != Type_Separator && token.Value.(Separator) != Separator_Comma {
|
_, err := p.expectSeparator(Separator_Comma)
|
||||||
return nil, nil, errors.New("expected ,")
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tokens = tokens[1:]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var paramType *Type
|
var paramType *Type
|
||||||
paramType, tokens, err = parseType(tokens)
|
paramType, err = p.expectType()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var paramName string
|
var paramName string
|
||||||
paramName, tokens, err = expectIdentifier(tokens)
|
paramName, err = p.expectIdentifier()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
parameters = append(parameters, ParsedParameter{Name: paramName, Type: *paramType})
|
parameters = append(parameters, ParsedParameter{Name: paramName, Type: *paramType})
|
||||||
}
|
}
|
||||||
|
|
||||||
_, tokens, err = expectSeparator(tokens, Separator_OpenCurly)
|
_, err = p.expectSeparator(Separator_OpenCurly)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: body, closing curly
|
// TODO: body, closing curly
|
||||||
|
|
||||||
return &ParsedFunction{Name: name, Parameters: parameters, ReturnType: *returnType, Body: body}, tokens, nil
|
_, err = p.expectSeparator(Separator_CloseCurly)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ParsedFunction{Name: name, Parameters: parameters, ReturnType: *returnType, Body: body}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parser(tokens []LexToken) (*ParsedFile, error) {
|
func (p *Parser) parseFile() (*ParsedFile, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
var functions []ParsedFunction
|
var functions []ParsedFunction
|
||||||
var imports []Import
|
var imports []Import
|
||||||
|
|
||||||
for len(tokens) > 0 {
|
for {
|
||||||
if tokens[0].Type == Type_Keyword && tokens[0].Value.(Keyword) == Keyword_Import {
|
token := p.peekToken()
|
||||||
|
if token == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("%+#v\n", token)
|
||||||
|
|
||||||
|
if token.Type == Type_Keyword && token.Value.(Keyword) == Keyword_Import {
|
||||||
var parsedImport *Import
|
var parsedImport *Import
|
||||||
parsedImport, tokens, err = parseImport(tokens)
|
parsedImport, err = p.expectImport()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -322,7 +342,7 @@ func parser(tokens []LexToken) (*ParsedFile, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var parsedFunction *ParsedFunction
|
var parsedFunction *ParsedFunction
|
||||||
parsedFunction, tokens, err = parseFunction(tokens)
|
parsedFunction, err = p.expectFunction()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user