asciigoat's INI parser https://asciigoat.org/ini
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

115 lines
2.3 KiB

package parser
import "asciigoat.org/core/lexer"
// Run parses the source
func (p *Parser) Run() error {
p.setDefaults()
return lexer.Run(p.lexStart)
}
func (p *Parser) lexStart() (lexer.StateFn, error) {
for {
r, _, err := p.p.ReadRune()
switch {
case err != nil:
return p.emitError("", err)
case IsNewLine(r):
// new line
p.p.UnreadRune()
p.p.AcceptNewLine()
p.stepLine()
case IsSpace(r):
// whitespace
p.stepString()
case IsCommentStart(r):
// switch to comment lexer
p.p.UnreadRune()
return p.lexComment, nil
case IsSectionStart(r):
// section
return p.lexSectionStart, nil
default:
// entry
p.p.UnreadRune()
return p.lexEntryStart, nil
}
}
}
func (p *Parser) lexComment() (lexer.StateFn, error) {
// until the end of the line
p.p.AcceptAll(IsNotNewLine)
err := p.emitString(TokenComment)
return p.lexStart, err
}
func (p *Parser) lexSectionStart() (lexer.StateFn, error) {
if err := p.emitString(TokenSectionStart); err != nil {
return nil, err
}
// remove whitespace between `[` and the name
if p.p.AcceptAll(IsSpaceNotNewLine) {
p.stepString()
}
if !p.p.AcceptAll(IsName) {
// no name
return p.emitError("section name missing", lexer.ErrUnacceptableRune)
}
if err := p.emitString(TokenSectionName); err != nil {
return nil, err
}
// remove whitespace between the name and the closing `]`
if p.p.AcceptAll(IsSpaceNotNewLine) {
p.stepString()
}
r, _, err := p.p.ReadRune()
switch {
case err != nil:
return p.emitError("", err)
case IsSectionEnd(r):
err := p.emitString(TokenSectionEnd)
return p.lexStart, err
default:
return p.emitInvalidRune(r)
}
}
func (p *Parser) lexEntryStart() (lexer.StateFn, error) {
p.p.AcceptAll(IsName)
if err := p.emitString(TokenFieldKey); err != nil {
return nil, err
}
// ignore whitespace between key and the '=' sign
if p.p.AcceptAll(IsSpaceNotNewLine) {
p.stepString()
}
r, _, err := p.p.ReadRune()
switch {
case err != nil:
return p.emitError("", err)
case r != RuneFieldEqual:
return p.emitInvalidRune(r)
}
// ignore whitespace between the '=' and the value
if p.p.AcceptAll(IsSpaceNotNewLine) {
p.stepString()
}
p.p.AcceptAll(IsNotNewLine)
if err := p.emitString(TokenFieldValue); err != nil {
return nil, err
}
return p.lexStart, err
}