167 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
package ini
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"sort"
 | 
						|
)
 | 
						|
 | 
						|
// Visitor is an interface used by walkers that will
 | 
						|
// traverse an array of ASTs.
 | 
						|
type Visitor interface {
 | 
						|
	VisitExpr(AST) error
 | 
						|
	VisitStatement(AST) error
 | 
						|
}
 | 
						|
 | 
						|
// DefaultVisitor is used to visit statements and expressions
 | 
						|
// and ensure that they are both of the correct format.
 | 
						|
// In addition, upon visiting this will build sections and populate
 | 
						|
// the Sections field which can be used to retrieve profile
 | 
						|
// configuration.
 | 
						|
type DefaultVisitor struct {
 | 
						|
	scope    string
 | 
						|
	Sections Sections
 | 
						|
}
 | 
						|
 | 
						|
// NewDefaultVisitor return a DefaultVisitor
 | 
						|
func NewDefaultVisitor() *DefaultVisitor {
 | 
						|
	return &DefaultVisitor{
 | 
						|
		Sections: Sections{
 | 
						|
			container: map[string]Section{},
 | 
						|
		},
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// VisitExpr visits expressions...
 | 
						|
func (v *DefaultVisitor) VisitExpr(expr AST) error {
 | 
						|
	t := v.Sections.container[v.scope]
 | 
						|
	if t.values == nil {
 | 
						|
		t.values = values{}
 | 
						|
	}
 | 
						|
 | 
						|
	switch expr.Kind {
 | 
						|
	case ASTKindExprStatement:
 | 
						|
		opExpr := expr.GetRoot()
 | 
						|
		switch opExpr.Kind {
 | 
						|
		case ASTKindEqualExpr:
 | 
						|
			children := opExpr.GetChildren()
 | 
						|
			if len(children) <= 1 {
 | 
						|
				return NewParseError("unexpected token type")
 | 
						|
			}
 | 
						|
 | 
						|
			rhs := children[1]
 | 
						|
 | 
						|
			if rhs.Root.Type() != TokenLit {
 | 
						|
				return NewParseError("unexpected token type")
 | 
						|
			}
 | 
						|
 | 
						|
			key := EqualExprKey(opExpr)
 | 
						|
			v, err := newValue(rhs.Root.ValueType, rhs.Root.base, rhs.Root.Raw())
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
 | 
						|
			t.values[key] = v
 | 
						|
		default:
 | 
						|
			return NewParseError(fmt.Sprintf("unsupported expression %v", expr))
 | 
						|
		}
 | 
						|
	default:
 | 
						|
		return NewParseError(fmt.Sprintf("unsupported expression %v", expr))
 | 
						|
	}
 | 
						|
 | 
						|
	v.Sections.container[v.scope] = t
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// VisitStatement visits statements...
 | 
						|
func (v *DefaultVisitor) VisitStatement(stmt AST) error {
 | 
						|
	switch stmt.Kind {
 | 
						|
	case ASTKindCompletedSectionStatement:
 | 
						|
		child := stmt.GetRoot()
 | 
						|
		if child.Kind != ASTKindSectionStatement {
 | 
						|
			return NewParseError(fmt.Sprintf("unsupported child statement: %T", child))
 | 
						|
		}
 | 
						|
 | 
						|
		name := string(child.Root.Raw())
 | 
						|
		v.Sections.container[name] = Section{}
 | 
						|
		v.scope = name
 | 
						|
	default:
 | 
						|
		return NewParseError(fmt.Sprintf("unsupported statement: %s", stmt.Kind))
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// Sections is a map of Section structures that represent
 | 
						|
// a configuration.
 | 
						|
type Sections struct {
 | 
						|
	container map[string]Section
 | 
						|
}
 | 
						|
 | 
						|
// GetSection will return section p. If section p does not exist,
 | 
						|
// false will be returned in the second parameter.
 | 
						|
func (t Sections) GetSection(p string) (Section, bool) {
 | 
						|
	v, ok := t.container[p]
 | 
						|
	return v, ok
 | 
						|
}
 | 
						|
 | 
						|
// values represents a map of union values.
 | 
						|
type values map[string]Value
 | 
						|
 | 
						|
// List will return a list of all sections that were successfully
 | 
						|
// parsed.
 | 
						|
func (t Sections) List() []string {
 | 
						|
	keys := make([]string, len(t.container))
 | 
						|
	i := 0
 | 
						|
	for k := range t.container {
 | 
						|
		keys[i] = k
 | 
						|
		i++
 | 
						|
	}
 | 
						|
 | 
						|
	sort.Strings(keys)
 | 
						|
	return keys
 | 
						|
}
 | 
						|
 | 
						|
// Section contains a name and values. This represent
 | 
						|
// a sectioned entry in a configuration file.
 | 
						|
type Section struct {
 | 
						|
	Name   string
 | 
						|
	values values
 | 
						|
}
 | 
						|
 | 
						|
// Has will return whether or not an entry exists in a given section
 | 
						|
func (t Section) Has(k string) bool {
 | 
						|
	_, ok := t.values[k]
 | 
						|
	return ok
 | 
						|
}
 | 
						|
 | 
						|
// ValueType will returned what type the union is set to. If
 | 
						|
// k was not found, the NoneType will be returned.
 | 
						|
func (t Section) ValueType(k string) (ValueType, bool) {
 | 
						|
	v, ok := t.values[k]
 | 
						|
	return v.Type, ok
 | 
						|
}
 | 
						|
 | 
						|
// Bool returns a bool value at k
 | 
						|
func (t Section) Bool(k string) bool {
 | 
						|
	return t.values[k].BoolValue()
 | 
						|
}
 | 
						|
 | 
						|
// Int returns an integer value at k
 | 
						|
func (t Section) Int(k string) int64 {
 | 
						|
	return t.values[k].IntValue()
 | 
						|
}
 | 
						|
 | 
						|
// Float64 returns a float value at k
 | 
						|
func (t Section) Float64(k string) float64 {
 | 
						|
	return t.values[k].FloatValue()
 | 
						|
}
 | 
						|
 | 
						|
// String returns the string value at k
 | 
						|
func (t Section) String(k string) string {
 | 
						|
	_, ok := t.values[k]
 | 
						|
	if !ok {
 | 
						|
		return ""
 | 
						|
	}
 | 
						|
	return t.values[k].StringValue()
 | 
						|
}
 |