// Package parser parses dosini-style files package parser import ( "io" "asciigoat.org/core/lexer" ) // Parser parses a dosini-style document type Parser struct { src *lexer.Reader pos lexer.Position queue []Token // OnSection is called after a [section] is parsed. // Returning an error will abort the process. OnSection func(pos lexer.Position, name, subname string, hasSubname bool) error // OnField is called after a `key = value` entry is parsed // Returning an error will abort the process. OnField func(pos lexer.Position, key, value string) error // OnComment is called after a comment is parsed // Returning an error will abort the process. OnComment func(pos lexer.Position, comment string) error // OnError is called after each parsing error, which you are allowed to // override. // OnError is called for EOF as well, but this error isn't returned as such by // Parser.Run(). The caller will receive (nil, nil) instead indicating the // processes terminated correctly. OnError func(pos lexer.Position, content string, err error) error } func defaultOnSection(_ lexer.Position, _, _ string, _ bool) error { return nil } func defaultOnField(_ lexer.Position, _, _ string) error { return nil } func defaultOnComment(_ lexer.Position, _ string) error { return nil } func defaultOnError(pos lexer.Position, content string, err error) error { return &lexer.Error{ Line: pos.Line, Column: pos.Column, Content: content, Err: err, } } func (p *Parser) setDefaults() { if p.OnSection == nil { p.OnSection = defaultOnSection } if p.OnField == nil { p.OnField = defaultOnField } if p.OnComment == nil { p.OnComment = defaultOnComment } if p.OnError == nil { p.OnError = defaultOnError } } // NewParser creates a dosini-style parser using // an [io.Reader] as source func NewParser(r io.Reader) *Parser { if r == nil { return nil } return &Parser{ src: lexer.NewReader(r), } }