aboutsummaryrefslogtreecommitdiff
path: root/visitor/default.go
blob: d8c817216617a22d4879ae907ff195ce9bff433d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package visitor

import (
	"errors"
	"fmt"
	"strings"

	"go.neonxp.ru/conf/model"
)

var (
	ErrEmptyQuery = errors.New("empty query")
	ErrNoChildKey = errors.New("no child key")
)

func NewDefault() *Default {
	return &Default{
		vars:     map[string]model.Values{},
		children: map[string]*Default{},
		args:     model.Values{},
	}
}

// Default просто собирает рекурсивно все переменные в дерево.
// На самом деле, для большинства сценариев конфигов его должно хватить.
type Default struct {
	vars     map[string]model.Values
	children map[string]*Default
	args     model.Values
}

func (p *Default) VisitDirective(ident string, args model.Values, body model.Body) error {
	p.children[ident] = NewDefault()
	p.children[ident].args = args
	return body.Execute(p.children[ident])
}

func (p *Default) VisitSetting(key string, values model.Values) error {
	p.vars[key] = values

	return nil
}

func (p *Default) Get(path string) (model.Values, error) {
	splitPath := strings.SplitN(path, ".", 2)
	switch len(splitPath) {
	case 1:
		if v, ok := p.vars[splitPath[0]]; ok {
			return v, nil
		}
		if child, ok := p.children[splitPath[0]]; ok {
			return child.args, nil
		}
		return nil, fmt.Errorf("%w: %s", ErrNoChildKey, splitPath[0])
	case 2:
		if child, ok := p.children[splitPath[0]]; ok {
			return child.Get(splitPath[1])
		}
		return nil, fmt.Errorf("%w: %s", ErrNoChildKey, splitPath[0])
	default:
		return nil, ErrEmptyQuery
	}
}