diff --git a/parser/lexer.go b/parser/lexer.go index fcffe77..420d500 100644 --- a/parser/lexer.go +++ b/parser/lexer.go @@ -26,22 +26,22 @@ func (p *Parser) lexStart() (lexer.StateFn, error) { case IsSpace(r): // whitespace p.stepRune() - default: - // token + case IsCommentStart(r): + // switch to comment lexer p.src.UnreadRune() - return p.lexToken, nil + return p.lexComment, nil + case IsSectionStart(r): + // section + p.stepRune() + return p.lexSectionStart, nil + default: + // entry + p.src.UnreadRune() + return p.lexEntryStart, nil } } } -func (p *Parser) lexToken() (lexer.StateFn, error) { - p.src.AcceptAll(IsNotSpace) - - p.pushString(TokenUnknown) - - return p.lexStart, nil -} - func (p *Parser) lexNewLine(r1 rune) { // r1 is warrantied to be either \n or \r r2, _, err := p.src.ReadRune() @@ -71,3 +71,49 @@ func (p *Parser) lexNewLine(r1 rune) { panic("unreachable") } } + +func (p *Parser) lexComment() (lexer.StateFn, error) { + // until the end of the line + p.src.AcceptAll(IsNotNewLine) + + err := p.OnComment(p.pos, p.src.Emit()) + return p.lexStart, err +} + +func (p *Parser) lexSectionStart() (lexer.StateFn, error) { + // remove whitespace between `[` and the name + if p.src.AcceptAll(IsSpaceNotNewLine) { + p.stepString() + } + + if !p.src.AcceptAll(IsName) { + // no name + return p.emitError("section name missing", lexer.ErrUnacceptableRune) + } + + p.pushString(TokenSectionName) + + var s0, s1 string + + // name starts + start := p.pos + s0 = p.src.String() + + if p.src.AcceptAll(IsSpaceNotNewLine) { + s1 = p.src.String() + } + } else { + } + + return nil, nil +} + +func (*Parser) lexEntryStart() (lexer.StateFn, error) { return nil, nil } + +func (p *Parser) lexToken() (lexer.StateFn, error) { + p.src.AcceptAll(IsNotSpace) + + p.pushString(TokenUnknown) + + return p.lexStart, nil +} diff --git a/parser/lexer_error.go b/parser/lexer_error.go index 9eaa98b..afe6fab 100644 --- a/parser/lexer_error.go +++ b/parser/lexer_error.go @@ -13,3 +13,7 @@ func (p *Parser) emitError(content string, err error) (lexer.StateFn, error) { return nil, err } } + +func (p *Parser) emitInvalidRune(r rune) (lexer.StateFn, error) { + return p.emitError(string([]rune{r}), lexer.ErrUnacceptableRune) +} diff --git a/parser/lexer_runes.go b/parser/lexer_runes.go index 308cbe9..4195085 100644 --- a/parser/lexer_runes.go +++ b/parser/lexer_runes.go @@ -1,19 +1,40 @@ package parser -import "asciigoat.org/core/lexer" +import ( + "strings" + + "asciigoat.org/core/lexer" +) var ( // IsNewLine tells if a rune represents a line break or the start of one IsNewLine = lexer.NewIsIn("\n\r") - // IsSpace tells if a rune is considered whitespace by unicode - IsSpace = lexer.IsSpace // IsNotNewLine tells if a rune is anything other than line breaks IsNotNewLine = lexer.NewIsNot(IsNewLine) // IsNotSpace tells if a rune is anything other than whitespace - IsNotSpace = lexer.NewIsNot(IsSpace) + IsNotSpace = lexer.NewIsNot(lexer.IsSpace) + // IsSpace tells if a rune is considered whitespace by unicode + IsSpace = lexer.IsSpace + + IsCommentStart = lexer.NewIsIn(";#") ) // IsSpaceNotNewLine indicates a rune is whitespace but not a new line func IsSpaceNotNewLine(r rune) bool { return IsSpace(r) && !IsNewLine(r) } + +func IsSectionStart(r rune) bool { + return r == '[' +} + +func IsName(r rune) bool { + switch { + case IsSpace(r): + return false + case strings.ContainsRune("=\"'[];#", r): + return false + default: + return true + } +}