1package ini 2 3import ( 4 "fmt" 5 "sort" 6) 7 8// Visitor is an interface used by walkers that will 9// traverse an array of ASTs. 10type Visitor interface { 11 VisitExpr(AST) error 12 VisitStatement(AST) error 13} 14 15// DefaultVisitor is used to visit statements and expressions 16// and ensure that they are both of the correct format. 17// In addition, upon visiting this will build sections and populate 18// the Sections field which can be used to retrieve profile 19// configuration. 20type DefaultVisitor struct { 21 scope string 22 Sections Sections 23} 24 25// NewDefaultVisitor return a DefaultVisitor 26func NewDefaultVisitor() *DefaultVisitor { 27 return &DefaultVisitor{ 28 Sections: Sections{ 29 container: map[string]Section{}, 30 }, 31 } 32} 33 34// VisitExpr visits expressions... 35func (v *DefaultVisitor) VisitExpr(expr AST) error { 36 t := v.Sections.container[v.scope] 37 if t.values == nil { 38 t.values = values{} 39 } 40 41 switch expr.Kind { 42 case ASTKindExprStatement: 43 opExpr := expr.GetRoot() 44 switch opExpr.Kind { 45 case ASTKindEqualExpr: 46 children := opExpr.GetChildren() 47 if len(children) <= 1 { 48 return NewParseError("unexpected token type") 49 } 50 51 rhs := children[1] 52 53 if rhs.Root.Type() != TokenLit { 54 return NewParseError("unexpected token type") 55 } 56 57 key := EqualExprKey(opExpr) 58 v, err := newValue(rhs.Root.ValueType, rhs.Root.base, rhs.Root.Raw()) 59 if err != nil { 60 return err 61 } 62 63 t.values[key] = v 64 default: 65 return NewParseError(fmt.Sprintf("unsupported expression %v", expr)) 66 } 67 default: 68 return NewParseError(fmt.Sprintf("unsupported expression %v", expr)) 69 } 70 71 v.Sections.container[v.scope] = t 72 return nil 73} 74 75// VisitStatement visits statements... 76func (v *DefaultVisitor) VisitStatement(stmt AST) error { 77 switch stmt.Kind { 78 case ASTKindCompletedSectionStatement: 79 child := stmt.GetRoot() 80 if child.Kind != ASTKindSectionStatement { 81 return NewParseError(fmt.Sprintf("unsupported child statement: %T", child)) 82 } 83 84 name := string(child.Root.Raw()) 85 v.Sections.container[name] = Section{} 86 v.scope = name 87 default: 88 return NewParseError(fmt.Sprintf("unsupported statement: %s", stmt.Kind)) 89 } 90 91 return nil 92} 93 94// Sections is a map of Section structures that represent 95// a configuration. 96type Sections struct { 97 container map[string]Section 98} 99 100// GetSection will return section p. If section p does not exist, 101// false will be returned in the second parameter. 102func (t Sections) GetSection(p string) (Section, bool) { 103 v, ok := t.container[p] 104 return v, ok 105} 106 107// values represents a map of union values. 108type values map[string]Value 109 110// List will return a list of all sections that were successfully 111// parsed. 112func (t Sections) List() []string { 113 keys := make([]string, len(t.container)) 114 i := 0 115 for k := range t.container { 116 keys[i] = k 117 i++ 118 } 119 120 sort.Strings(keys) 121 return keys 122} 123 124// Section contains a name and values. This represent 125// a sectioned entry in a configuration file. 126type Section struct { 127 Name string 128 values values 129} 130 131// Has will return whether or not an entry exists in a given section 132func (t Section) Has(k string) bool { 133 _, ok := t.values[k] 134 return ok 135} 136 137// ValueType will returned what type the union is set to. If 138// k was not found, the NoneType will be returned. 139func (t Section) ValueType(k string) (ValueType, bool) { 140 v, ok := t.values[k] 141 return v.Type, ok 142} 143 144// Bool returns a bool value at k 145func (t Section) Bool(k string) bool { 146 return t.values[k].BoolValue() 147} 148 149// Int returns an integer value at k 150func (t Section) Int(k string) int64 { 151 return t.values[k].IntValue() 152} 153 154// Float64 returns a float value at k 155func (t Section) Float64(k string) float64 { 156 return t.values[k].FloatValue() 157} 158 159// String returns the string value at k 160func (t Section) String(k string) string { 161 _, ok := t.values[k] 162 if !ok { 163 return "" 164 } 165 return t.values[k].StringValue() 166} 167