bombadillo/config/parser.go

128 lines
2.9 KiB
Go
Raw Permalink Normal View History

/*
* Copyright (C) 2022 Brian Evans
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package config
import (
"fmt"
"io"
"strings"
)
//------------------------------------------------\\
// + + + T Y P E S + + + \\
//--------------------------------------------------\\
type Parser struct {
s *scanner
row int
buffer struct {
token Token
size int
}
}
type Config struct {
2019-09-12 05:53:36 +00:00
// Bookmarks gopher.Bookmarks
2019-11-10 18:41:12 +00:00
Bookmarks struct {
Titles, Links []string
2019-09-12 05:53:36 +00:00
}
2019-11-10 18:41:12 +00:00
Settings []KeyValue
Certs []KeyValue
}
type KeyValue struct {
Key string
Value string
}
//------------------------------------------------\\
// + + + R E C E I V E R S + + + \\
//--------------------------------------------------\\
func (p *Parser) scan() (current Token) {
if p.buffer.size != 0 {
p.buffer.size = 0
return p.buffer.token
}
current = p.s.scan()
p.buffer.token = current
return
}
func (p *Parser) parseKeyValue() (KeyValue, error) {
kv := KeyValue{}
t1 := p.scan()
kv.Key = strings.TrimSpace(t1.val)
if t := p.scan(); t.kind == TOK_VALUE {
kv.Value = strings.TrimSpace(t.val)
} else {
return kv, fmt.Errorf("Got non-value expected VALUE on row %d", p.row)
}
if t := p.scan(); t.kind != TOK_NEWLINE {
return kv, fmt.Errorf("Expected NEWLINE, got %q on row %d", t.kind, p.row)
}
return kv, nil
}
func (p *Parser) unscan() { p.buffer.size = 1 }
func (p *Parser) Parse() (Config, error) {
p.row = 1
section := ""
c := Config{}
for {
if t := p.scan(); t.kind == TOK_NEWLINE {
p.row++
} else if t.kind == TOK_SECTION {
section = strings.ToUpper(t.val)
} else if t.kind == TOK_EOF {
break
} else if t.kind == TOK_KEY {
p.unscan()
keyval, err := p.parseKeyValue()
if err != nil {
return Config{}, err
}
switch section {
case "BOOKMARKS":
2019-09-12 05:53:36 +00:00
c.Bookmarks.Titles = append(c.Bookmarks.Titles, keyval.Value)
c.Bookmarks.Links = append(c.Bookmarks.Links, keyval.Key)
2019-09-27 05:08:57 +00:00
case "CERTS":
c.Certs = append(c.Certs, keyval)
case "SETTINGS":
c.Settings = append(c.Settings, keyval)
}
} else if t.kind == TOK_ERROR {
return Config{}, fmt.Errorf("Error on row %d: %s", p.row, t.val)
}
}
return c, nil
}
//------------------------------------------------\\
// + + + F U N C T I O N S + + + \\
//--------------------------------------------------\\
func NewParser(r io.Reader) *Parser {
return &Parser{s: NewScanner(r)}
}