Ejemplo n.º 1
0
func (p *toml) lookupTable(t *ast.Table, keys []string) (*ast.Table, error) {
	for _, s := range keys {
		val, exists := t.Fields[s]
		if !exists {
			tbl := &ast.Table{
				Line: p.line,
				Name: s,
				Type: ast.TableTypeNormal,
			}
			if t.Fields == nil {
				t.Fields = make(map[string]interface{})
			}
			t.Fields[s] = tbl
			t = tbl
			continue
		}
		switch v := val.(type) {
		case *ast.Table:
			t = v
		case []*ast.Table:
			t = v[len(v)-1]
		case *ast.KeyValue:
			return nil, fmt.Errorf("key `%s' is in conflict with line %d", s, v.Line)
		default:
			return nil, fmt.Errorf("BUG: key `%s' is in conflict but it's unknown type `%T'", s, v)
		}
	}
	return t, nil
}
Ejemplo n.º 2
0
func (p *toml) setArrayTable(t *ast.Table, buf []rune, begin, end int) {
	name := string(buf[begin:end])
	if t, exists := p.tableMap[name]; exists && t.Type == ast.TableTypeNormal {
		p.Error(fmt.Errorf("table `%s' is in conflict with %v table in line %d", name, t.Type, t.Line))
	}
	names := splitTableKey(name)
	t, err := p.lookupTable(t, names[:len(names)-1])
	if err != nil {
		p.Error(err)
	}
	last := names[len(names)-1]
	tbl := &ast.Table{
		Position: ast.Position{begin, end},
		Line:     p.line,
		Name:     last,
		Type:     ast.TableTypeArray,
	}
	switch v := t.Fields[last].(type) {
	case nil:
		if t.Fields == nil {
			t.Fields = make(map[string]interface{})
		}
		t.Fields[last] = []*ast.Table{tbl}
	case []*ast.Table:
		t.Fields[last] = append(v, tbl)
	case *ast.KeyValue:
		p.Error(fmt.Errorf("key `%s' is in conflict with line %d", last, v.Line))
	default:
		p.Error(fmt.Errorf("BUG: key `%s' is in conflict but it's unknown type `%T'", last, v))
	}
	p.currentTable = tbl
	p.tableMap[name] = p.currentTable
}
Ejemplo n.º 3
0
// UnmarshalTable applies the contents of an ast.Table to the value pointed at by v.
//
// UnmarshalTable will mapped to v that according to following rules:
//
//	TOML strings to string
//	TOML integers to any int type
//	TOML floats to float32 or float64
//	TOML booleans to bool
//	TOML datetimes to time.Time
//	TOML arrays to any type of slice or []interface{}
//	TOML tables to struct
//	TOML array of tables to slice of struct
func UnmarshalTable(t *ast.Table, v interface{}) (err error) {
	if v == nil {
		return fmt.Errorf("v must not be nil")
	}
	rv := reflect.ValueOf(v)
	if kind := rv.Kind(); kind != reflect.Ptr && kind != reflect.Map {
		return fmt.Errorf("v must be a pointer or map")
	}
	for rv.Kind() == reflect.Ptr {
		rv = rv.Elem()
	}
	if err, ok := setUnmarshaler(rv, string(t.Data)); ok {
		return err
	}
	for key, val := range t.Fields {
		switch av := val.(type) {
		case *ast.KeyValue:
			fv, fieldName, found := findField(rv, key)
			if !found {
				return fmt.Errorf("line %d: field corresponding to `%s' is not defined in `%T'", av.Line, key, v)
			}
			switch fv.Kind() {
			case reflect.Map:
				mv := reflect.New(fv.Type().Elem()).Elem()
				if err := UnmarshalTable(t, mv.Addr().Interface()); err != nil {
					return err
				}
				fv.SetMapIndex(reflect.ValueOf(fieldName), mv)
			default:
				if err := setValue(fv, av.Value); err != nil {
					return fmt.Errorf("line %d: %v.%s: %v", av.Line, rv.Type(), fieldName, err)
				}
				if rv.Kind() == reflect.Map {
					rv.SetMapIndex(reflect.ValueOf(fieldName), fv)
				}
			}
		case *ast.Table:
			fv, fieldName, found := findField(rv, key)
			if !found {
				return fmt.Errorf("line %d: field corresponding to `%s' is not defined in `%T'", av.Line, key, v)
			}
			if err, ok := setUnmarshaler(fv, string(av.Data)); ok {
				if err != nil {
					return err
				}
				continue
			}
			for fv.Kind() == reflect.Ptr {
				fv.Set(reflect.New(fv.Type().Elem()))
				fv = fv.Elem()
			}
			switch fv.Kind() {
			case reflect.Struct:
				vv := reflect.New(fv.Type()).Elem()
				if err := UnmarshalTable(av, vv.Addr().Interface()); err != nil {
					return err
				}
				fv.Set(vv)
				if rv.Kind() == reflect.Map {
					rv.SetMapIndex(reflect.ValueOf(fieldName), fv)
				}
			case reflect.Map:
				mv := reflect.MakeMap(fv.Type())
				if err := UnmarshalTable(av, mv.Interface()); err != nil {
					return err
				}
				fv.Set(mv)
			default:
				return fmt.Errorf("line %d: `%v.%s' must be struct or map, but %v given", av.Line, rv.Type(), fieldName, fv.Kind())
			}
		case []*ast.Table:
			fv, fieldName, found := findField(rv, key)
			if !found {
				return fmt.Errorf("line %d: field corresponding to `%s' is not defined in `%T'", av[0].Line, key, v)
			}
			data := make([]string, 0, len(av))
			for _, tbl := range av {
				data = append(data, string(tbl.Data))
			}
			if err, ok := setUnmarshaler(fv, strings.Join(data, "\n")); ok {
				if err != nil {
					return err
				}
				continue
			}
			t := fv.Type().Elem()
			pc := 0
			for ; t.Kind() == reflect.Ptr; pc++ {
				t = t.Elem()
			}
			if fv.Kind() != reflect.Slice {
				return fmt.Errorf("line %d: `%v.%s' must be slice type, but %v given", av[0].Line, rv.Type(), fieldName, fv.Kind())
			}
			for _, tbl := range av {
				var vv reflect.Value
				switch t.Kind() {
				case reflect.Map:
					vv = reflect.MakeMap(t)
					if err := UnmarshalTable(tbl, vv.Interface()); err != nil {
						return err
					}
				default:
					vv = reflect.New(t).Elem()
					if err := UnmarshalTable(tbl, vv.Addr().Interface()); err != nil {
						return err
					}
				}
				for i := 0; i < pc; i++ {
					vv = vv.Addr()
					pv := reflect.New(vv.Type()).Elem()
					pv.Set(vv)
					vv = pv
				}
				fv.Set(reflect.Append(fv, vv))
			}
			if rv.Kind() == reflect.Map {
				rv.SetMapIndex(reflect.ValueOf(fieldName), fv)
			}
		default:
			return fmt.Errorf("BUG: unknown type `%T'", t)
		}
	}
	return nil
}