func UnpackArgs()

in starlark/unpack.go [93:179]


func UnpackArgs(fnname string, args Tuple, kwargs []Tuple, pairs ...interface{}) error {
	nparams := len(pairs) / 2
	var defined intset
	defined.init(nparams)

	paramName := func(x interface{}) (name string, skipNone bool) { // (no free variables)
		name = x.(string)
		if strings.HasSuffix(name, "??") {
			name = strings.TrimSuffix(name, "??")
			skipNone = true
		} else if name[len(name)-1] == '?' {
			name = name[:len(name)-1]
		}

		return name, skipNone
	}

	// positional arguments
	if len(args) > nparams {
		return fmt.Errorf("%s: got %d arguments, want at most %d",
			fnname, len(args), nparams)
	}
	for i, arg := range args {
		defined.set(i)
		name, skipNone := paramName(pairs[2*i])
		if skipNone {
			if _, isNone := arg.(NoneType); isNone {
				continue
			}
		}
		if err := unpackOneArg(arg, pairs[2*i+1]); err != nil {
			return fmt.Errorf("%s: for parameter %s: %s", fnname, name, err)
		}
	}

	// keyword arguments
kwloop:
	for _, item := range kwargs {
		name, arg := item[0].(String), item[1]
		for i := 0; i < nparams; i++ {
			pName, skipNone := paramName(pairs[2*i])
			if pName == string(name) {
				// found it
				if defined.set(i) {
					return fmt.Errorf("%s: got multiple values for keyword argument %s",
						fnname, name)
				}

				if skipNone {
					if _, isNone := arg.(NoneType); isNone {
						continue kwloop
					}
				}

				ptr := pairs[2*i+1]
				if err := unpackOneArg(arg, ptr); err != nil {
					return fmt.Errorf("%s: for parameter %s: %s", fnname, name, err)
				}
				continue kwloop
			}
		}
		err := fmt.Errorf("%s: unexpected keyword argument %s", fnname, name)
		names := make([]string, 0, nparams)
		for i := 0; i < nparams; i += 2 {
			param, _ := paramName(pairs[i])
			names = append(names, param)
		}
		if n := spell.Nearest(string(name), names); n != "" {
			err = fmt.Errorf("%s (did you mean %s?)", err.Error(), n)
		}
		return err
	}

	// Check that all non-optional parameters are defined.
	// (We needn't check the first len(args).)
	for i := len(args); i < nparams; i++ {
		name := pairs[2*i].(string)
		if strings.HasSuffix(name, "?") {
			break // optional
		}
		if !defined.get(i) {
			return fmt.Errorf("%s: missing argument for %s", fnname, name)
		}
	}

	return nil
}