1package toml 2 3import ( 4 "errors" 5 "fmt" 6 "io" 7 "os" 8 "runtime" 9 "strings" 10) 11 12type tomlValue struct { 13 value interface{} // string, int64, uint64, float64, bool, time.Time, [] of any of this list 14 position Position 15} 16 17// Tree is the result of the parsing of a TOML file. 18type Tree struct { 19 values map[string]interface{} // string -> *tomlValue, *Tree, []*Tree 20 position Position 21} 22 23func newTree() *Tree { 24 return &Tree{ 25 values: make(map[string]interface{}), 26 position: Position{}, 27 } 28} 29 30// TreeFromMap initializes a new Tree object using the given map. 31func TreeFromMap(m map[string]interface{}) (*Tree, error) { 32 result, err := toTree(m) 33 if err != nil { 34 return nil, err 35 } 36 return result.(*Tree), nil 37} 38 39// Position returns the position of the tree. 40func (t *Tree) Position() Position { 41 return t.position 42} 43 44// Has returns a boolean indicating if the given key exists. 45func (t *Tree) Has(key string) bool { 46 if key == "" { 47 return false 48 } 49 return t.HasPath(strings.Split(key, ".")) 50} 51 52// HasPath returns true if the given path of keys exists, false otherwise. 53func (t *Tree) HasPath(keys []string) bool { 54 return t.GetPath(keys) != nil 55} 56 57// Keys returns the keys of the toplevel tree (does not recurse). 58func (t *Tree) Keys() []string { 59 keys := make([]string, len(t.values)) 60 i := 0 61 for k := range t.values { 62 keys[i] = k 63 i++ 64 } 65 return keys 66} 67 68// Get the value at key in the Tree. 69// Key is a dot-separated path (e.g. a.b.c). 70// Returns nil if the path does not exist in the tree. 71// If keys is of length zero, the current tree is returned. 72func (t *Tree) Get(key string) interface{} { 73 if key == "" { 74 return t 75 } 76 comps, err := parseKey(key) 77 if err != nil { 78 return nil 79 } 80 return t.GetPath(comps) 81} 82 83// GetPath returns the element in the tree indicated by 'keys'. 84// If keys is of length zero, the current tree is returned. 85func (t *Tree) GetPath(keys []string) interface{} { 86 if len(keys) == 0 { 87 return t 88 } 89 subtree := t 90 for _, intermediateKey := range keys[:len(keys)-1] { 91 value, exists := subtree.values[intermediateKey] 92 if !exists { 93 return nil 94 } 95 switch node := value.(type) { 96 case *Tree: 97 subtree = node 98 case []*Tree: 99 // go to most recent element 100 if len(node) == 0 { 101 return nil 102 } 103 subtree = node[len(node)-1] 104 default: 105 return nil // cannot navigate through other node types 106 } 107 } 108 // branch based on final node type 109 switch node := subtree.values[keys[len(keys)-1]].(type) { 110 case *tomlValue: 111 return node.value 112 default: 113 return node 114 } 115} 116 117// GetPosition returns the position of the given key. 118func (t *Tree) GetPosition(key string) Position { 119 if key == "" { 120 return t.position 121 } 122 return t.GetPositionPath(strings.Split(key, ".")) 123} 124 125// GetPositionPath returns the element in the tree indicated by 'keys'. 126// If keys is of length zero, the current tree is returned. 127func (t *Tree) GetPositionPath(keys []string) Position { 128 if len(keys) == 0 { 129 return t.position 130 } 131 subtree := t 132 for _, intermediateKey := range keys[:len(keys)-1] { 133 value, exists := subtree.values[intermediateKey] 134 if !exists { 135 return Position{0, 0} 136 } 137 switch node := value.(type) { 138 case *Tree: 139 subtree = node 140 case []*Tree: 141 // go to most recent element 142 if len(node) == 0 { 143 return Position{0, 0} 144 } 145 subtree = node[len(node)-1] 146 default: 147 return Position{0, 0} 148 } 149 } 150 // branch based on final node type 151 switch node := subtree.values[keys[len(keys)-1]].(type) { 152 case *tomlValue: 153 return node.position 154 case *Tree: 155 return node.position 156 case []*Tree: 157 // go to most recent element 158 if len(node) == 0 { 159 return Position{0, 0} 160 } 161 return node[len(node)-1].position 162 default: 163 return Position{0, 0} 164 } 165} 166 167// GetDefault works like Get but with a default value 168func (t *Tree) GetDefault(key string, def interface{}) interface{} { 169 val := t.Get(key) 170 if val == nil { 171 return def 172 } 173 return val 174} 175 176// Set an element in the tree. 177// Key is a dot-separated path (e.g. a.b.c). 178// Creates all necessary intermediate trees, if needed. 179func (t *Tree) Set(key string, value interface{}) { 180 t.SetPath(strings.Split(key, "."), value) 181} 182 183// SetPath sets an element in the tree. 184// Keys is an array of path elements (e.g. {"a","b","c"}). 185// Creates all necessary intermediate trees, if needed. 186func (t *Tree) SetPath(keys []string, value interface{}) { 187 subtree := t 188 for _, intermediateKey := range keys[:len(keys)-1] { 189 nextTree, exists := subtree.values[intermediateKey] 190 if !exists { 191 nextTree = newTree() 192 subtree.values[intermediateKey] = nextTree // add new element here 193 } 194 switch node := nextTree.(type) { 195 case *Tree: 196 subtree = node 197 case []*Tree: 198 // go to most recent element 199 if len(node) == 0 { 200 // create element if it does not exist 201 subtree.values[intermediateKey] = append(node, newTree()) 202 } 203 subtree = node[len(node)-1] 204 } 205 } 206 207 var toInsert interface{} 208 209 switch value.(type) { 210 case *Tree: 211 toInsert = value 212 case []*Tree: 213 toInsert = value 214 case *tomlValue: 215 toInsert = value 216 default: 217 toInsert = &tomlValue{value: value} 218 } 219 220 subtree.values[keys[len(keys)-1]] = toInsert 221} 222 223// createSubTree takes a tree and a key and create the necessary intermediate 224// subtrees to create a subtree at that point. In-place. 225// 226// e.g. passing a.b.c will create (assuming tree is empty) tree[a], tree[a][b] 227// and tree[a][b][c] 228// 229// Returns nil on success, error object on failure 230func (t *Tree) createSubTree(keys []string, pos Position) error { 231 subtree := t 232 for _, intermediateKey := range keys { 233 nextTree, exists := subtree.values[intermediateKey] 234 if !exists { 235 tree := newTree() 236 tree.position = pos 237 subtree.values[intermediateKey] = tree 238 nextTree = tree 239 } 240 241 switch node := nextTree.(type) { 242 case []*Tree: 243 subtree = node[len(node)-1] 244 case *Tree: 245 subtree = node 246 default: 247 return fmt.Errorf("unknown type for path %s (%s): %T (%#v)", 248 strings.Join(keys, "."), intermediateKey, nextTree, nextTree) 249 } 250 } 251 return nil 252} 253 254// LoadReader creates a Tree from any io.Reader. 255func LoadReader(reader io.Reader) (tree *Tree, err error) { 256 defer func() { 257 if r := recover(); r != nil { 258 if _, ok := r.(runtime.Error); ok { 259 panic(r) 260 } 261 err = errors.New(r.(string)) 262 } 263 }() 264 tree = parseToml(lexToml(reader)) 265 return 266} 267 268// Load creates a Tree from a string. 269func Load(content string) (tree *Tree, err error) { 270 return LoadReader(strings.NewReader(content)) 271} 272 273// LoadFile creates a Tree from a file. 274func LoadFile(path string) (tree *Tree, err error) { 275 file, err := os.Open(path) 276 if err != nil { 277 return nil, err 278 } 279 defer file.Close() 280 return LoadReader(file) 281} 282