// https://github.com/google/skylark/blob/master/doc/spec.md#string-interpolation
546671
func interpolate(format string, x Value) (Value, error) {
	var buf bytes.Buffer
	path := make([]Value, 0, 4)
	index := 0
	for {
		i := strings.IndexByte(format, '%')
		if i < 0 {
			buf.WriteString(format)
			break
		}
		buf.WriteString(format[:i])
		format = format[i+1:]

		if format != "" && format[0] == '%' {
			buf.WriteByte('%')
			format = format[1:]
			continue
		}

		var arg Value
		if format != "" && format[0] == '(' {
			// keyword argument: %(name)s.
			format = format[1:]
			j := strings.IndexByte(format, ')')
			if j < 0 {
				return nil, fmt.Errorf("incomplete format key")
			}
			key := format[:j]
			if dict, ok := x.(Mapping); !ok {
				return nil, fmt.Errorf("format requires a mapping")
			} else if v, found, _ := dict.Get(String(key)); found {
				arg = v
			} else {
				return nil, fmt.Errorf("key not found: %s", key)
			}
			format = format[j+1:]
		} else {
			// positional argument: %s.
			if tuple, ok := x.(Tuple); ok {
				if index >= len(tuple) {
					return nil, fmt.Errorf("not enough arguments for format string")
				}
				arg = tuple[index]
			} else if index > 0 {
				return nil, fmt.Errorf("not enough arguments for format string")
			} else {
				arg = x
			}
		}

		// NOTE: Skylark does not support any of these optional Python features:
		// - optional conversion flags: [#0- +], etc.
		// - optional minimum field width (number or *).
		// - optional precision (.123 or *)
		// - optional length modifier

		// conversion type
		if format == "" {
			return nil, fmt.Errorf("incomplete format")
		}
		switch c := format[0]; c {
		case 's', 'r':
			if str, ok := AsString(arg); ok && c == 's' {
				buf.WriteString(str)
			} else {
				writeValue(&buf, arg, path)
			}
		case 'd', 'i', 'o', 'x', 'X':
			i, err := NumberToInt(arg)
			if err != nil {
				return nil, fmt.Errorf("%%%c format requires integer: %v", c, err)
			}
			switch c {
			case 'd', 'i':
				buf.WriteString(i.bigint.Text(10))
			case 'o':
				buf.WriteString(i.bigint.Text(8))
			case 'x':
				buf.WriteString(i.bigint.Text(16))
			case 'X':
				buf.WriteString(strings.ToUpper(i.bigint.Text(16)))
			}
		case 'e', 'f', 'g', 'E', 'F', 'G':
			f, ok := AsFloat(arg)
			if !ok {
				return nil, fmt.Errorf("%%%c format requires float, not %s", c, arg.Type())
			}
			switch c {
			case 'e':
				fmt.Fprintf(&buf, "%e", f)
			case 'f':
				fmt.Fprintf(&buf, "%f", f)
			case 'g':
				fmt.Fprintf(&buf, "%g", f)
			case 'E':
				fmt.Fprintf(&buf, "%E", f)
			case 'F':
				fmt.Fprintf(&buf, "%F", f)
			case 'G':
				fmt.Fprintf(&buf, "%G", f)
			}
		case 'c':
			switch arg := arg.(type) {
			case Int:
				// chr(int)
				r, err := AsInt32(arg)
				if err != nil || r < 0 || r > unicode.MaxRune {
					return nil, fmt.Errorf("%%c format requires a valid Unicode code point, got %s", arg)
				}
				buf.WriteRune(rune(r))
			case String:
				r, size := utf8.DecodeRuneInString(string(arg))
				if size != len(arg) {
					return nil, fmt.Errorf("%%c format requires a single-character string")
				}
				buf.WriteRune(r)
			default:
				return nil, fmt.Errorf("%%c format requires int or single-character string, not %s", arg.Type())
			}
		case '%':
			buf.WriteByte('%')
		default:
			return nil, fmt.Errorf("unknown conversion %%%c", c)
		}
		format = format[1:]
		index++
	}

	if tuple, ok := x.(Tuple); ok && index < len(tuple) {
		return nil, fmt.Errorf("too many arguments for format string")
	}

	return String(buf.String()), nil
}
410489
func interpolationFuncDirname() ast.Function {
	return ast.Function{
		ArgTypes:   []ast.Type{ast.TypeString},
		ReturnType: ast.TypeString,
		Callback: func(args []interface{}) (interface{}, error) {
			return filepath.Dir(args[0].(string)), nil
		},
	}
}
665918
func interpolationFuncValues(vs map[string]ast.Variable) ast.Function {
	return ast.Function{
		ArgTypes:   []ast.Type{ast.TypeMap},
		ReturnType: ast.TypeList,
		Callback: func(args []interface{}) (interface{}, error) {
			mapVar := args[0].(map[string]ast.Variable)
			keys := make([]string, 0)

			for k, _ := range mapVar {
				keys = append(keys, k)
			}

			sort.Strings(keys)

			values := make([]string, len(keys))
			for index, key := range keys {
				if value, ok := mapVar[key].Value.(string); ok {
					values[index] = value
				} else {
					return "", fmt.Errorf("values(): %q has element with bad type %s",
						key, mapVar[key].Type)
				}
			}

			variable, err := hil.InterfaceToVariable(values)
			if err != nil {
				return nil, err
			}

			return variable.Value, nil
		},
	}
}
983142
func (s *RadialSimplifier) MultiLineString(mls orb.MultiLineString) orb.MultiLineString {
	return multiLineString(s, mls)
}
983014
func (v *CrazyNesting) String() string {
	if v == nil {
		return "<nil>"
	}

	var fields [4]string
	i := 0
	if v.StringField != nil {
		fields[i] = fmt.Sprintf("StringField: %v", *(v.StringField))
		i++
	}
	if v.SetField != nil {
		fields[i] = fmt.Sprintf("SetField: %v", v.SetField)
		i++
	}
	fields[i] = fmt.Sprintf("ListField: %v", v.ListField)
	i++
	if v.BinaryField != nil {
		fields[i] = fmt.Sprintf("BinaryField: %v", v.BinaryField)
		i++
	}

	return fmt.Sprintf("CrazyNesting{%v}", strings.Join(fields[:i], ", "))
}
743363
func interpolationFuncMap() ast.Function {
	return ast.Function{
		ArgTypes:     []ast.Type{},
		ReturnType:   ast.TypeMap,
		Variadic:     true,
		VariadicType: ast.TypeAny,
		Callback: func(args []interface{}) (interface{}, error) {
			outputMap := make(map[string]ast.Variable)

			if len(args)%2 != 0 {
				return nil, fmt.Errorf("requires an even number of arguments, got %d", len(args))
			}

			var firstType *ast.Type
			for i := 0; i < len(args); i += 2 {
				key, ok := args[i].(string)
				if !ok {
					return nil, fmt.Errorf("argument %d represents a key, so it must be a string", i+1)
				}
				val := args[i+1]
				variable, err := hil.InterfaceToVariable(val)
				if err != nil {
					return nil, err
				}
				// Enforce map type homogeneity
				if firstType == nil {
					firstType = &variable.Type
				} else if variable.Type != *firstType {
					return nil, fmt.Errorf("all map values must have the same type, got %s then %s", firstType.Printable(), variable.Type.Printable())
				}
				// Check for duplicate keys
				if _, ok := outputMap[key]; ok {
					return nil, fmt.Errorf("argument %d is a duplicate key: %q", i+1, key)
				}
				outputMap[key] = variable
			}

			return outputMap, nil
		},
	}
}
99405
func interpolationFuncMax() ast.Function {
	return ast.Function{
		ArgTypes:     []ast.Type{ast.TypeFloat},
		ReturnType:   ast.TypeFloat,
		Variadic:     true,
		VariadicType: ast.TypeFloat,
		Callback: func(args []interface{}) (interface{}, error) {
			max := args[0].(float64)

			for i := 1; i < len(args); i++ {
				max = math.Max(max, args[i].(float64))
			}

			return max, nil
		},
	}
}
1140580
func interpolationFuncFormatList() ast.Function {
	return ast.Function{
		ArgTypes:     []ast.Type{ast.TypeAny},
		Variadic:     true,
		VariadicType: ast.TypeAny,
		ReturnType:   ast.TypeList,
		Callback: func(args []interface{}) (interface{}, error) {
			// Make a copy of the variadic part of args
			// to avoid modifying the original.
			varargs := make([]interface{}, len(args)-1)
			copy(varargs, args[1:])

			// Verify we have some arguments
			if len(varargs) == 0 {
				return nil, fmt.Errorf("no arguments to formatlist")
			}

			// Convert arguments that are lists into slices.
			// Confirm along the way that all lists have the same length (n).
			var n int
			listSeen := false
			for i := 1; i < len(args); i++ {
				s, ok := args[i].([]ast.Variable)
				if !ok {
					continue
				}

				// Mark that we've seen at least one list
				listSeen = true

				// Convert the ast.Variable to a slice of strings
				parts, err := listVariableValueToStringSlice(s)
				if err != nil {
					return nil, err
				}

				// otherwise the list is sent down to be indexed
				varargs[i-1] = parts

				// Check length
				if n == 0 {
					// first list we've seen
					n = len(parts)
					continue
				}
				if n != len(parts) {
					return nil, fmt.Errorf("format: mismatched list lengths: %d != %d", n, len(parts))
				}
			}

			// If we didn't see a list this is an error because we
			// can't determine the return value length.
			if !listSeen {
				return nil, fmt.Errorf(
					"formatlist requires at least one list argument")
			}

			// Do the formatting.
			format := args[0].(string)

			// Generate a list of formatted strings.
			list := make([]string, n)
			fmtargs := make([]interface{}, len(varargs))
			for i := 0; i < n; i++ {
				for j, arg := range varargs {
					switch arg := arg.(type) {
					default:
						fmtargs[j] = arg
					case []string:
						fmtargs[j] = arg[i]
					}
				}
				list[i] = fmt.Sprintf(format, fmtargs...)
			}
			return stringSliceToVariableValue(list), nil
		},
	}
}
1203377
func (c *Config) InterpolatedVariables() map[string][]InterpolatedVariable {
	result := make(map[string][]InterpolatedVariable)
	for source, rc := range c.rawConfigs() {
		for _, v := range rc.Variables {
			result[source] = append(result[source], v)
		}
	}
	return result
}
258952
func string_strip(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) {
	var chars string
	if err := UnpackPositionalArgs(fnname, args, kwargs, 0, &chars); err != nil {
		return nil, err
	}
	recv := string(recv_.(String))
	var s string
	switch fnname[0] {
	case 's': // strip
		if chars != "" {
			s = strings.Trim(recv, chars)
		} else {
			s = strings.TrimSpace(recv)
		}
	case 'l': // lstrip
		if chars != "" {
			s = strings.TrimLeft(recv, chars)
		} else {
			s = strings.TrimLeftFunc(recv, unicode.IsSpace)
		}
	case 'r': // rstrip
		if chars != "" {
			s = strings.TrimRight(recv, chars)
		} else {
			s = strings.TrimRightFunc(recv, unicode.IsSpace)
		}
	}
	return String(s), nil
}
35083
func (i *Interpolator) Interpolate() error {
	for pos := 0; ; pos++ {
		r, _, err := i.template.ReadRune()
		if err != nil {
			if err == io.EOF {
				break
			}
			return err
		}
		if err := i.parse(r, pos); err != nil {
			return err
		}
	}
	return i.finish()
}
193044
func (g *MultiLineString) LineString(i int) *LineString {
	offset := 0
	if i > 0 {
		offset = g.ends[i-1]
	}
	return NewLineStringFlat(g.layout, g.flatCoords[offset:g.ends[i]])
}
74012
func interpolationFuncKeys(vs map[string]ast.Variable) ast.Function {
	return ast.Function{
		ArgTypes:   []ast.Type{ast.TypeMap},
		ReturnType: ast.TypeList,
		Callback: func(args []interface{}) (interface{}, error) {
			mapVar := args[0].(map[string]ast.Variable)
			keys := make([]string, 0)

			for k, _ := range mapVar {
				keys = append(keys, k)
			}

			sort.Strings(keys)

			// Keys are guaranteed to be strings
			return stringSliceToVariableValue(keys), nil
		},
	}
}
1121573
func interpolationFuncLookup(vs map[string]ast.Variable) ast.Function {
	return ast.Function{
		ArgTypes:     []ast.Type{ast.TypeMap, ast.TypeString},
		ReturnType:   ast.TypeString,
		Variadic:     true,
		VariadicType: ast.TypeString,
		Callback: func(args []interface{}) (interface{}, error) {
			defaultValue := ""
			defaultValueSet := false
			if len(args) > 2 {
				defaultValue = args[2].(string)
				defaultValueSet = true
			}
			if len(args) > 3 {
				return "", fmt.Errorf("lookup() takes no more than three arguments")
			}
			index := args[1].(string)
			mapVar := args[0].(map[string]ast.Variable)

			v, ok := mapVar[index]
			if !ok {
				if defaultValueSet {
					return defaultValue, nil
				} else {
					return "", fmt.Errorf(
						"lookup failed to find '%s'",
						args[1].(string))
				}
			}
			if v.Type != ast.TypeString {
				return nil, fmt.Errorf(
					"lookup() may only be used with flat maps, this map contains elements of %s",
					v.Type.Printable())
			}

			return v.Value.(string), nil
		},
	}
}
1023036
func interpolationFuncDistinct() ast.Function {
	return ast.Function{
		ArgTypes:     []ast.Type{ast.TypeList},
		ReturnType:   ast.TypeList,
		Variadic:     true,
		VariadicType: ast.TypeList,
		Callback: func(args []interface{}) (interface{}, error) {
			var list []string

			if len(args) != 1 {
				return nil, fmt.Errorf("accepts only one argument.")
			}

			if argument, ok := args[0].([]ast.Variable); ok {
				for _, element := range argument {
					if element.Type != ast.TypeString {
						return nil, fmt.Errorf(
							"only works for flat lists, this list contains elements of %s",
							element.Type.Printable())
					}
					list = appendIfMissing(list, element.Value.(string))
				}
			}

			return stringSliceToVariableValue(list), nil
		},
	}
}
1085008
func SetNestedStringSlice(obj map[string]interface{}, value []string, fields ...string) error {
	m := make([]interface{}, 0, len(value)) // convert []string into []interface{}
	for _, v := range value {
		m = append(m, v)
	}
	return setNestedFieldNoCopy(obj, m, fields...)
}
638438
func string_format(fnname string, recv_ Value, args Tuple, kwargs []Tuple) (Value, error) {
	format := string(recv_.(String))
	var auto, manual bool // kinds of positional indexing used
	path := make([]Value, 0, 4)
	var buf bytes.Buffer
	index := 0
	for {
		literal := format
		i := strings.IndexByte(format, '{')
		if i >= 0 {
			literal = format[:i]
		}

		// Replace "}}" with "}" in non-field portion, rejecting a lone '}'.
		for {
			j := strings.IndexByte(literal, '}')
			if j < 0 {
				buf.WriteString(literal)
				break
			}
			if len(literal) == j+1 || literal[j+1] != '}' {
				return nil, fmt.Errorf("single '}' in format")
			}
			buf.WriteString(literal[:j+1])
			literal = literal[j+2:]
		}

		if i < 0 {
			break // end of format string
		}

		if i+1 < len(format) && format[i+1] == '{' {
			// "{{" means a literal '{'
			buf.WriteByte('{')
			format = format[i+2:]
			continue
		}

		format = format[i+1:]
		i = strings.IndexByte(format, '}')
		if i < 0 {
			return nil, fmt.Errorf("unmatched '{' in format")
		}

		var arg Value
		conv := "s"
		var spec string

		field := format[:i]
		format = format[i+1:]

		var name string
		if i := strings.IndexByte(field, '!'); i < 0 {
			// "name" or "name:spec"
			if i := strings.IndexByte(field, ':'); i < 0 {
				name = field
			} else {
				name = field[:i]
				spec = field[i+1:]
			}
		} else {
			// "name!conv" or "name!conv:spec"
			name = field[:i]
			field = field[i+1:]
			// "conv" or "conv:spec"
			if i := strings.IndexByte(field, ':'); i < 0 {
				conv = field
			} else {
				conv = field[:i]
				spec = field[i+1:]
			}
		}

		if name == "" {
			// "{}": automatic indexing
			if manual {
				return nil, fmt.Errorf("cannot switch from manual field specification to automatic field numbering")
			}
			auto = true
			if index >= len(args) {
				return nil, fmt.Errorf("tuple index out of range")
			}
			arg = args[index]
			index++
		} else if num, err := strconv.Atoi(name); err == nil && !strings.HasPrefix(name, "-") {
			// positional argument
			if auto {
				return nil, fmt.Errorf("cannot switch from automatic field numbering to manual field specification")
			}
			manual = true
			if num >= len(args) {
				return nil, fmt.Errorf("tuple index out of range")
			} else {
				arg = args[num]
			}
		} else {
			// keyword argument
			for _, kv := range kwargs {
				if string(kv[0].(String)) == name {
					arg = kv[1]
					break
				}
			}
			if arg == nil {
				// Skylark does not support Python's x.y or a[i] syntaxes,
				// or nested use of {...}.
				if strings.Contains(name, ".") {
					return nil, fmt.Errorf("attribute syntax x.y is not supported in replacement fields: %s", name)
				}
				if strings.Contains(name, "[") {
					return nil, fmt.Errorf("element syntax a[i] is not supported in replacement fields: %s", name)
				}
				if strings.Contains(name, "{") {
					return nil, fmt.Errorf("nested replacement fields not supported")
				}
				return nil, fmt.Errorf("keyword %s not found", name)
			}
		}

		if spec != "" {
			// Skylark does not support Python's format_spec features.
			return nil, fmt.Errorf("format spec features not supported in replacement fields: %s", spec)
		}

		switch conv {
		case "s":
			if str, ok := AsString(arg); ok {
				buf.WriteString(str)
			} else {
				writeValue(&buf, arg, path)
			}
		case "r":
			writeValue(&buf, arg, path)
		default:
			return nil, fmt.Errorf("unknown conversion %q", conv)
		}
	}
	return String(buf.String()), nil
}