Files
sift/vendor/github.com/itchyny/gojq/func.go
T
kyle 9444a35322 p1: /v2/scrape, /v1/fetch, auth, CLI, contract tests
Single Fetcher.Fetch on the Guard that holds DenyPrefixes. skipTlsVerification
is ignored. No 502. keys add writes the secret only to --out. Release binary
has no -test-allow-prefix.
2026-09-22 21:54:01 -07:00

2191 lines
44 KiB
Go

package gojq
import (
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
"iter"
"maps"
"math"
"math/big"
"net/url"
"reflect"
"regexp"
"slices"
"sort"
"strconv"
"strings"
"sync"
"time"
"unicode"
"unicode/utf8"
"github.com/itchyny/timefmt-go"
)
//go:generate go run -modfile=go.dev.mod _tools/gen_builtin.go -i builtin.jq -o builtin.go
var builtinFuncDefs map[string][]*FuncDef
const (
argcount0 = 1 << iota
argcount1
argcount2
argcount3
)
type function struct {
argcount int
iter bool
callback func(any, []any) any
}
func (fn function) accept(cnt int) bool {
return fn.argcount&(1<<cnt) != 0
}
var internalFuncs map[string]function
func init() {
internalFuncs = map[string]function{
"empty": argFunc0(nil),
"path": argFunc1(nil),
"env": argFunc0(nil),
"builtins": argFunc0(nil),
"input": argFunc0(nil),
"modulemeta": argFunc0(nil),
"debug": argFunc1(nil),
"abs": argFunc0(funcAbs),
"length": argFunc0(funcLength),
"utf8bytelength": argFunc0(funcUtf8ByteLength),
"keys": argFunc0(funcKeys),
"has": argFunc1(funcHas),
"add": argFunc0(funcAdd),
"toboolean": argFunc0(funcToBoolean),
"tonumber": argFunc0(funcToNumber),
"tostring": argFunc0(funcToString),
"type": argFunc0(funcType),
"reverse": argFunc0(funcReverse),
"contains": argFunc1(funcContains),
"inside": argFunc1(funcInside),
"indices": argFunc1(funcIndices),
"index": argFunc1(funcIndex),
"rindex": argFunc1(funcRindex),
"startswith": argFunc1(funcStartsWith),
"endswith": argFunc1(funcEndsWith),
"ltrimstr": argFunc1(funcLtrimstr),
"rtrimstr": argFunc1(funcRtrimstr),
"trimstr": argFunc1(funcTrimstr),
"ltrim": argFunc0(funcLtrim),
"rtrim": argFunc0(funcRtrim),
"trim": argFunc0(funcTrim),
"explode": argFunc0(funcExplode),
"implode": argFunc0(funcImplode),
"split": argFunc1(funcSplit),
"join": argFunc1(funcJoin),
"ascii_downcase": argFunc0(funcASCIIDowncase),
"ascii_upcase": argFunc0(funcASCIIUpcase),
"tojson": argFunc0(funcToJSON),
"fromjson": argFunc0(funcFromJSON),
"format": argFunc1(funcFormat),
"_tohtml": argFunc0(funcToHTML),
"_touri": argFunc0(funcToURI),
"_tourid": argFunc0(funcToURId),
"_tocsv": argFunc0(funcToCSV),
"_totsv": argFunc0(funcToTSV),
"_tosh": argFunc0(funcToSh),
"_tobase64": argFunc0(funcToBase64),
"_tobase64d": argFunc0(funcToBase64d),
"_index": argFunc2(funcIndex2),
"_slice": argFunc3(funcSlice),
"_plus": argFunc0(funcOpPlus),
"_negate": argFunc0(funcOpNegate),
"_add": argFunc2(funcOpAdd),
"_subtract": argFunc2(funcOpSub),
"_multiply": argFunc2(funcOpMul),
"_divide": argFunc2(funcOpDiv),
"_modulo": argFunc2(funcOpMod),
"_alternative": argFunc2(funcOpAlt),
"_equal": argFunc2(funcOpEq),
"_notequal": argFunc2(funcOpNe),
"_greater": argFunc2(funcOpGt),
"_less": argFunc2(funcOpLt),
"_greatereq": argFunc2(funcOpGe),
"_lesseq": argFunc2(funcOpLe),
"flatten": {argcount0 | argcount1, false, funcFlatten},
"_range": {argcount3, true, funcRange},
"min": argFunc0(funcMin),
"_min_by": argFunc1(funcMinBy),
"max": argFunc0(funcMax),
"_max_by": argFunc1(funcMaxBy),
"sort": argFunc0(funcSort),
"_sort_by": argFunc1(funcSortBy),
"_group_by": argFunc1(funcGroupBy),
"unique": argFunc0(funcUnique),
"_unique_by": argFunc1(funcUniqueBy),
"sin": mathFunc("sin", math.Sin),
"cos": mathFunc("cos", math.Cos),
"tan": mathFunc("tan", math.Tan),
"asin": mathFunc("asin", math.Asin),
"acos": mathFunc("acos", math.Acos),
"atan": mathFunc("atan", math.Atan),
"sinh": mathFunc("sinh", math.Sinh),
"cosh": mathFunc("cosh", math.Cosh),
"tanh": mathFunc("tanh", math.Tanh),
"asinh": mathFunc("asinh", math.Asinh),
"acosh": mathFunc("acosh", math.Acosh),
"atanh": mathFunc("atanh", math.Atanh),
"floor": mathFunc("floor", math.Floor),
"round": mathFunc("round", math.Round),
"nearbyint": mathFunc("nearbyint", math.RoundToEven),
"rint": mathFunc("rint", math.RoundToEven),
"ceil": mathFunc("ceil", math.Ceil),
"trunc": mathFunc("trunc", math.Trunc),
"significand": mathFunc("significand", funcSignificand),
"fabs": mathFunc("fabs", math.Abs),
"sqrt": mathFunc("sqrt", math.Sqrt),
"cbrt": mathFunc("cbrt", math.Cbrt),
"exp": mathFunc("exp", math.Exp),
"exp10": mathFunc("exp10", funcExp10),
"exp2": mathFunc("exp2", math.Exp2),
"expm1": mathFunc("expm1", math.Expm1),
"frexp": argFunc0(funcFrexp),
"modf": argFunc0(funcModf),
"log": mathFunc("log", math.Log),
"log10": mathFunc("log10", math.Log10),
"log1p": mathFunc("log1p", math.Log1p),
"log2": mathFunc("log2", math.Log2),
"logb": mathFunc("logb", math.Logb),
"gamma": mathFunc("gamma", math.Gamma),
"tgamma": mathFunc("tgamma", math.Gamma),
"lgamma": mathFunc("lgamma", funcLgamma),
"erf": mathFunc("erf", math.Erf),
"erfc": mathFunc("erfc", math.Erfc),
"j0": mathFunc("j0", math.J0),
"j1": mathFunc("j1", math.J1),
"y0": mathFunc("y0", math.Y0),
"y1": mathFunc("y1", math.Y1),
"atan2": mathFunc2("atan2", math.Atan2),
"copysign": mathFunc2("copysign", math.Copysign),
"drem": mathFunc2("drem", funcDrem),
"fdim": mathFunc2("fdim", math.Dim),
"fmax": mathFunc2("fmax", funcFmax),
"fmin": mathFunc2("fmin", funcFmin),
"fmod": mathFunc2("fmod", math.Mod),
"hypot": mathFunc2("hypot", math.Hypot),
"jn": mathFunc2("jn", funcJn),
"nextafter": mathFunc2("nextafter", math.Nextafter),
"nexttoward": mathFunc2("nexttoward", math.Nextafter),
"remainder": mathFunc2("remainder", math.Remainder),
"ldexp": mathFunc2("ldexp", funcLdexp),
"scalb": mathFunc2("scalb", funcLdexp),
"scalbln": mathFunc2("scalbln", funcLdexp),
"yn": mathFunc2("yn", funcYn),
"pow": mathFunc2("pow", math.Pow),
"fma": mathFunc3("fma", math.FMA),
"infinite": argFunc0(funcInfinite),
"isfinite": argFunc0(funcIsfinite),
"isinfinite": argFunc0(funcIsinfinite),
"nan": argFunc0(funcNan),
"isnan": argFunc0(funcIsnan),
"isnormal": argFunc0(funcIsnormal),
"setpath": argFunc2(funcSetpath),
"delpaths": argFunc1(funcDelpaths),
"getpath": argFunc1(funcGetpath),
"transpose": argFunc0(funcTranspose),
"bsearch": argFunc1(funcBsearch),
"gmtime": argFunc0(funcGmtime),
"localtime": argFunc0(funcLocaltime),
"mktime": argFunc0(funcMktime),
"strftime": argFunc1(funcStrftime),
"strflocaltime": argFunc1(funcStrflocaltime),
"strptime": argFunc1(funcStrptime),
"now": argFunc0(funcNow),
"_match": argFunc3(nil),
"_captures": argFunc0(funcCaptures),
"error": {argcount0 | argcount1, false, funcError},
"halt": argFunc0(funcHalt),
"halt_error": {argcount0 | argcount1, false, funcHaltError},
}
}
func argFunc0(f func(any) any) function {
return function{
argcount0, false, func(v any, _ []any) any {
return f(v)
},
}
}
func argFunc1(f func(_, _ any) any) function {
return function{
argcount1, false, func(v any, args []any) any {
return f(v, args[0])
},
}
}
func argFunc2(f func(_, _, _ any) any) function {
return function{
argcount2, false, func(v any, args []any) any {
return f(v, args[0], args[1])
},
}
}
func argFunc3(f func(_, _, _, _ any) any) function {
return function{
argcount3, false, func(v any, args []any) any {
return f(v, args[0], args[1], args[2])
},
}
}
func mathFunc(name string, f func(float64) float64) function {
return argFunc0(func(v any) any {
x, ok := toFloat(v)
if !ok {
return &func0TypeError{name, v}
}
return f(x)
})
}
func mathFunc2(name string, f func(_, _ float64) float64) function {
return argFunc2(func(_, x, y any) any {
l, ok := toFloat(x)
if !ok {
return &func0TypeError{name, x}
}
r, ok := toFloat(y)
if !ok {
return &func0TypeError{name, y}
}
return f(l, r)
})
}
func mathFunc3(name string, f func(_, _, _ float64) float64) function {
return argFunc3(func(_, a, b, c any) any {
x, ok := toFloat(a)
if !ok {
return &func0TypeError{name, a}
}
y, ok := toFloat(b)
if !ok {
return &func0TypeError{name, b}
}
z, ok := toFloat(c)
if !ok {
return &func0TypeError{name, c}
}
return f(x, y, z)
})
}
func funcAbs(v any) any {
switch v := v.(type) {
case int:
if v >= 0 {
return v
}
return negate(v)
case float64:
return math.Abs(v)
case *big.Int:
if v.Sign() >= 0 {
return v
}
return new(big.Int).Abs(v)
case json.Number:
if !strings.HasPrefix(v.String(), "-") {
return v
}
return v[1:]
default:
return &func0TypeError{"abs", v}
}
}
func funcLength(v any) any {
switch v := v.(type) {
case nil:
return 0
case int:
if v >= 0 {
return v
}
return negate(v)
case float64:
return math.Abs(v)
case *big.Int:
if v.Sign() >= 0 {
return v
}
return new(big.Int).Abs(v)
case json.Number:
if !strings.HasPrefix(v.String(), "-") {
return v
}
return v[1:]
case string:
return len([]rune(v))
case []any:
return len(v)
case map[string]any:
return len(v)
default:
return &func0TypeError{"length", v}
}
}
func funcUtf8ByteLength(v any) any {
s, ok := v.(string)
if !ok {
return &func0TypeError{"utf8bytelength", v}
}
return len(s)
}
func funcKeys(v any) any {
switch v := v.(type) {
case []any:
w := make([]any, len(v))
for i := range v {
w[i] = i
}
return w
case map[string]any:
w := make([]any, len(v))
for i, k := range keys(v) {
w[i] = k
}
return w
default:
return &func0TypeError{"keys", v}
}
}
func keys(v map[string]any) []string {
w := make([]string, len(v))
var i int
for k := range v {
w[i] = k
i++
}
sort.Strings(w)
return w
}
func values(v any) ([]any, bool) {
switch v := v.(type) {
case []any:
return v, true
case map[string]any:
vs := make([]any, len(v))
for i, k := range keys(v) {
vs[i] = v[k]
}
return vs, true
default:
return nil, false
}
}
func funcHas(v, x any) any {
switch v := v.(type) {
case []any:
if x, ok := toInt(x); ok {
return 0 <= x && x < len(v)
}
case map[string]any:
if x, ok := x.(string); ok {
_, ok := v[x]
return ok
}
case nil:
return false
}
return &func1TypeError{"has", v, x}
}
func funcAdd(v any) any {
vs, ok := values(v)
if !ok {
return &func0TypeError{"add", v}
}
return add(slices.Values(vs))
}
func add(xs iter.Seq[any]) any {
var v any
for x := range xs {
switch x := x.(type) {
case nil:
continue
case string:
switch w := v.(type) {
case nil:
var sb strings.Builder
sb.WriteString(x)
v = &sb
continue
case *strings.Builder:
w.WriteString(x)
continue
}
case []any:
switch w := v.(type) {
case nil:
s := make([]any, len(x))
copy(s, x)
v = s
continue
case []any:
v = append(w, x...)
continue
}
case map[string]any:
switch w := v.(type) {
case nil:
v = maps.Clone(x)
continue
case map[string]any:
maps.Copy(w, x)
continue
}
}
if sb, ok := v.(*strings.Builder); ok {
v = sb.String()
}
v = funcOpAdd(nil, v, x)
if err, ok := v.(error); ok {
return err
}
}
if sb, ok := v.(*strings.Builder); ok {
v = sb.String()
}
return v
}
func funcToBoolean(v any) any {
switch v := v.(type) {
case bool:
return v
case string:
switch v {
case "true":
return true
case "false":
return false
default:
return &func0WrapError{"toboolean", v, errors.New("invalid boolean")}
}
default:
return &func0TypeError{"toboolean", v}
}
}
func funcToNumber(v any) any {
switch v := v.(type) {
case int, float64, *big.Int, json.Number:
return v
case string:
if !newLexer(v).validNumber() {
return &func0WrapError{"tonumber", v, errors.New("invalid number")}
}
return toNumber(v)
default:
return &func0TypeError{"tonumber", v}
}
}
func toNumber(v string) any {
return parseNumber(json.Number(v))
}
func funcToString(v any) any {
if s, ok := v.(string); ok {
return s
}
return funcToJSON(v)
}
func funcType(v any) any {
return TypeOf(v)
}
func funcReverse(v any) any {
vs, ok := v.([]any)
if !ok {
return &func0TypeError{"reverse", v}
}
ws := make([]any, len(vs))
for i, v := range vs {
ws[len(ws)-i-1] = v
}
return ws
}
func funcContains(v, x any) any {
return binopTypeSwitch(v, x,
func(l, r int) any { return l == r },
func(l, r float64) any { return l == r },
func(l, r *big.Int) any { return l.Cmp(r) == 0 },
func(l, r string) any { return strings.Contains(l, r) },
func(l, r []any) any {
R:
for _, r := range r {
for _, l := range l {
if funcContains(l, r) == true {
continue R
}
}
return false
}
return true
},
func(l, r map[string]any) any {
if len(l) < len(r) {
return false
}
for k, r := range r {
if l, ok := l[k]; !ok || funcContains(l, r) != true {
return false
}
}
return true
},
func(l, r any) any {
if l == r {
return true
}
return &func1TypeError{"contains", l, r}
},
)
}
func funcInside(v, x any) any {
return funcContains(x, v)
}
func funcIndices(v, x any) any {
return indexFunc("indices", v, x, indices)
}
func indices(vs, xs []any) any {
rs := []any{}
if len(xs) == 0 {
return rs
}
for i := range len(vs) - len(xs) + 1 {
if Compare(vs[i:i+len(xs)], xs) == 0 {
rs = append(rs, i)
}
}
return rs
}
func funcIndex(v, x any) any {
return indexFunc("index", v, x, func(vs, xs []any) any {
if len(xs) == 0 {
return nil
}
for i := range len(vs) - len(xs) + 1 {
if Compare(vs[i:i+len(xs)], xs) == 0 {
return i
}
}
return nil
})
}
func funcRindex(v, x any) any {
return indexFunc("rindex", v, x, func(vs, xs []any) any {
if len(xs) == 0 {
return nil
}
for i := len(vs) - len(xs); i >= 0; i-- {
if Compare(vs[i:i+len(xs)], xs) == 0 {
return i
}
}
return nil
})
}
func indexFunc(name string, v, x any, f func(_, _ []any) any) any {
switch v := v.(type) {
case nil:
return nil
case []any:
switch x := x.(type) {
case []any:
return f(v, x)
default:
return f(v, []any{x})
}
case string:
if x, ok := x.(string); ok {
return f(explode(v), explode(x))
}
return &func1TypeError{name, v, x}
default:
return &func1TypeError{name, v, x}
}
}
func funcStartsWith(v, x any) any {
s, ok := v.(string)
if !ok {
return &func1TypeError{"startswith", v, x}
}
t, ok := x.(string)
if !ok {
return &func1TypeError{"startswith", v, x}
}
return strings.HasPrefix(s, t)
}
func funcEndsWith(v, x any) any {
s, ok := v.(string)
if !ok {
return &func1TypeError{"endswith", v, x}
}
t, ok := x.(string)
if !ok {
return &func1TypeError{"endswith", v, x}
}
return strings.HasSuffix(s, t)
}
func funcLtrimstr(v, x any) any {
s, ok := v.(string)
if !ok {
return &func1TypeError{"ltrimstr", v, x}
}
t, ok := x.(string)
if !ok {
return &func1TypeError{"ltrimstr", v, x}
}
return strings.TrimPrefix(s, t)
}
func funcRtrimstr(v, x any) any {
s, ok := v.(string)
if !ok {
return &func1TypeError{"rtrimstr", v, x}
}
t, ok := x.(string)
if !ok {
return &func1TypeError{"rtrimstr", v, x}
}
return strings.TrimSuffix(s, t)
}
func funcTrimstr(v, x any) any {
s, ok := v.(string)
if !ok {
return &func1TypeError{"trimstr", v, x}
}
t, ok := x.(string)
if !ok {
return &func1TypeError{"trimstr", v, x}
}
return strings.TrimSuffix(strings.TrimPrefix(s, t), t)
}
func funcLtrim(v any) any {
s, ok := v.(string)
if !ok {
return &func0TypeError{"ltrim", v}
}
return strings.TrimLeftFunc(s, unicode.IsSpace)
}
func funcRtrim(v any) any {
s, ok := v.(string)
if !ok {
return &func0TypeError{"rtrim", v}
}
return strings.TrimRightFunc(s, unicode.IsSpace)
}
func funcTrim(v any) any {
s, ok := v.(string)
if !ok {
return &func0TypeError{"trim", v}
}
return strings.TrimSpace(s)
}
func funcExplode(v any) any {
s, ok := v.(string)
if !ok {
return &func0TypeError{"explode", v}
}
return explode(s)
}
func explode(s string) []any {
xs := make([]any, len([]rune(s)))
var i int
for _, r := range s {
xs[i] = int(r)
i++
}
return xs
}
func funcImplode(v any) any {
vs, ok := v.([]any)
if !ok {
return &func0TypeError{"implode", v}
}
var sb strings.Builder
sb.Grow(len(vs))
for _, v := range vs {
if r, ok := toInt(v); ok {
if 0 <= r && r <= utf8.MaxRune {
sb.WriteRune(rune(r))
} else {
sb.WriteRune(utf8.RuneError)
}
} else {
return &func0TypeError{"implode", vs}
}
}
return sb.String()
}
func funcSplit(v, x any) any {
s, ok := v.(string)
if !ok {
return &func0TypeError{"split", v}
}
t, ok := x.(string)
if !ok {
return &func0TypeError{"split", x}
}
ss := strings.Split(s, t)
xs := make([]any, len(ss))
for i, s := range ss {
xs[i] = s
}
return xs
}
func funcJoin(v, x any) any {
vs, ok := values(v)
if !ok {
return &func1TypeError{"join", v, x}
}
if len(vs) == 0 {
return ""
}
return add(func(yield func(any) bool) {
for i, v := range vs {
s := x
if i == 0 {
s = ""
}
if !yield(s) {
return
}
switch w := v.(type) {
case bool, int, float64, *big.Int, json.Number:
v = jsonMarshal(w)
}
if !yield(v) {
return
}
}
})
}
func funcASCIIDowncase(v any) any {
s, ok := v.(string)
if !ok {
return &func0TypeError{"ascii_downcase", v}
}
return strings.Map(func(r rune) rune {
if 'A' <= r && r <= 'Z' {
return r + ('a' - 'A')
}
return r
}, s)
}
func funcASCIIUpcase(v any) any {
s, ok := v.(string)
if !ok {
return &func0TypeError{"ascii_upcase", v}
}
return strings.Map(func(r rune) rune {
if 'a' <= r && r <= 'z' {
return r - ('a' - 'A')
}
return r
}, s)
}
func funcToJSON(v any) any {
return jsonMarshal(v)
}
func funcFromJSON(v any) any {
s, ok := v.(string)
if !ok {
return &func0TypeError{"fromjson", v}
}
var w any
dec := json.NewDecoder(strings.NewReader(s))
dec.UseNumber()
if err := dec.Decode(&w); err != nil {
return &func0WrapError{"fromjson", v, err}
}
if _, err := dec.Token(); err != io.EOF {
return &func0TypeError{"fromjson", v}
}
return w
}
func funcFormat(v, x any) any {
s, ok := x.(string)
if !ok {
return &func0TypeError{"format", x}
}
format := "@" + s
f := formatToFunc(format)
if f == nil {
return &formatNotFoundError{format}
}
return internalFuncs[f.Name].callback(v, nil)
}
var htmlEscaper = strings.NewReplacer(
`<`, "&lt;",
`>`, "&gt;",
`&`, "&amp;",
`'`, "&apos;",
`"`, "&quot;",
)
func funcToHTML(v any) any {
switch x := funcToString(v).(type) {
case string:
return htmlEscaper.Replace(x)
default:
return x
}
}
func funcToURI(v any) any {
switch x := funcToString(v).(type) {
case string:
return strings.ReplaceAll(url.QueryEscape(x), "+", "%20")
default:
return x
}
}
func funcToURId(v any) any {
switch x := funcToString(v).(type) {
case string:
x, err := url.QueryUnescape(strings.ReplaceAll(x, "+", "%2B"))
if err != nil {
return &func0WrapError{"@urid", v, err}
}
return x
default:
return x
}
}
var csvEscaper = strings.NewReplacer(
`"`, `""`,
"\x00", `\0`,
)
func funcToCSV(v any) any {
return formatJoin("csv", v, ",", func(s string) string {
return `"` + csvEscaper.Replace(s) + `"`
})
}
var tsvEscaper = strings.NewReplacer(
"\t", `\t`,
"\r", `\r`,
"\n", `\n`,
"\\", `\\`,
"\x00", `\0`,
)
func funcToTSV(v any) any {
return formatJoin("tsv", v, "\t", tsvEscaper.Replace)
}
var shEscaper = strings.NewReplacer(
"'", `'\''`,
"\x00", `\0`,
)
func funcToSh(v any) any {
if _, ok := v.([]any); !ok {
v = []any{v}
}
return formatJoin("sh", v, " ", func(s string) string {
return "'" + shEscaper.Replace(s) + "'"
})
}
func formatJoin(typ string, v any, sep string, escape func(string) string) any {
vs, ok := v.([]any)
if !ok {
return &func0TypeError{"@" + typ, v}
}
ss := make([]string, len(vs))
for i, v := range vs {
switch v := v.(type) {
case []any, map[string]any:
return &formatRowError{typ, v}
case string:
ss[i] = escape(v)
default:
if s := jsonMarshal(v); s != "null" || typ == "sh" {
ss[i] = s
}
}
}
return strings.Join(ss, sep)
}
func funcToBase64(v any) any {
switch x := funcToString(v).(type) {
case string:
return base64.StdEncoding.EncodeToString([]byte(x))
default:
return x
}
}
func funcToBase64d(v any) any {
switch x := funcToString(v).(type) {
case string:
if i := strings.IndexRune(x, base64.StdPadding); i >= 0 {
x = x[:i]
}
y, err := base64.RawStdEncoding.DecodeString(x)
if err != nil {
return &func0WrapError{"@base64d", v, err}
}
return string(y)
default:
return x
}
}
func funcIndex2(_, v, x any) any {
switch x := x.(type) {
case string:
switch v := v.(type) {
case nil:
return nil
case map[string]any:
return v[x]
default:
return &expectedObjectError{v}
}
case int, float64, *big.Int, json.Number:
i, _ := toInt(x)
switch v := v.(type) {
case nil:
return nil
case []any:
return index(v, i)
case string:
return indexString(v, i)
default:
return &expectedArrayError{v}
}
case []any:
switch v := v.(type) {
case nil:
return nil
case []any:
return indices(v, x)
default:
return &expectedArrayError{v}
}
case map[string]any:
if v == nil {
return nil
}
start, ok := x["start"]
if !ok {
return &expectedStartEndError{x}
}
end, ok := x["end"]
if !ok {
return &expectedStartEndError{x}
}
return funcSlice(nil, v, end, start)
default:
switch v.(type) {
case []any:
return &arrayIndexNotNumberError{x}
case string:
return &stringIndexNotNumberError{x}
default:
return &objectKeyNotStringError{x}
}
}
}
func index(vs []any, i int) any {
i = clampIndex(i, -1, len(vs))
if 0 <= i && i < len(vs) {
return vs[i]
}
return nil
}
func indexString(s string, i int) any {
l := len([]rune(s))
i = clampIndex(i, -1, l)
if 0 <= i && i < l {
for _, r := range s {
if i--; i < 0 {
return string(r)
}
}
}
return nil
}
func funcSlice(_, v, e, s any) (r any) {
switch v := v.(type) {
case nil:
return nil
case []any:
return slice(v, e, s)
case string:
return sliceString(v, e, s)
default:
return &expectedArrayError{v}
}
}
func slice(vs []any, e, s any) any {
var start, end int
if s != nil {
if i, ok := toInt(s); ok {
start = clampIndex(i, 0, len(vs))
} else {
return &arrayIndexNotNumberError{s}
}
}
if e != nil {
if i, ok := toIntCeil(e); ok {
end = clampIndex(i, start, len(vs))
} else {
return &arrayIndexNotNumberError{e}
}
} else {
end = len(vs)
}
return vs[start:end]
}
func sliceString(v string, e, s any) any {
var start, end int
l := len([]rune(v))
if s != nil {
if i, ok := toInt(s); ok {
start = clampIndex(i, 0, l)
} else {
return &stringIndexNotNumberError{s}
}
}
if e != nil {
if i, ok := toIntCeil(e); ok {
end = clampIndex(i, start, l)
} else {
return &stringIndexNotNumberError{e}
}
} else {
end = l
}
if start < l {
for i := range v {
if start--; start < 0 {
start = i
break
}
}
} else {
start = len(v)
}
if end < l {
for i := range v {
if end--; end < 0 {
end = i
break
}
}
} else {
end = len(v)
}
return v[start:end]
}
func clampIndex(i, minimum, maximum int) int {
if i < 0 {
i += maximum
}
if i < minimum {
return minimum
} else if i < maximum {
return i
} else {
return maximum
}
}
func funcFlatten(v any, args []any) any {
vs, ok := values(v)
if !ok {
return &func0TypeError{"flatten", v}
}
var depth float64
if len(args) == 0 {
depth = -1
} else {
depth, ok = toFloat(args[0])
if !ok {
return &func0TypeError{"flatten", args[0]}
}
if lt(depth, 0) {
return &flattenDepthError{depth}
}
}
return flatten([]any{}, vs, depth)
}
func flatten(xs, vs []any, depth float64) []any {
for _, v := range vs {
if vs, ok := v.([]any); ok && depth != 0 {
xs = flatten(xs, vs, depth-1)
} else {
xs = append(xs, v)
}
}
return xs
}
type rangeIter struct {
value, end, step any
}
func (iter *rangeIter) Next() (any, bool) {
if Compare(iter.step, 0)*Compare(iter.value, iter.end) >= 0 {
return nil, false
}
v := iter.value
iter.value = funcOpAdd(nil, v, iter.step)
return v, true
}
func funcRange(_ any, xs []any) any {
for _, x := range xs {
switch x.(type) {
case int, float64, *big.Int, json.Number:
default:
return &func0TypeError{"range", x}
}
}
return &rangeIter{xs[0], xs[1], xs[2]}
}
func funcMin(v any) any {
vs, ok := v.([]any)
if !ok {
return &func0TypeError{"min", v}
}
return minMaxBy(vs, vs, true)
}
func funcMinBy(v, x any) any {
vs, ok := v.([]any)
if !ok {
return &func1TypeError{"min_by", v, x}
}
xs, ok := x.([]any)
if !ok {
return &func1TypeError{"min_by", v, x}
}
if len(vs) != len(xs) {
return &func1WrapError{"min_by", v, x, &lengthMismatchError{}}
}
return minMaxBy(vs, xs, true)
}
func funcMax(v any) any {
vs, ok := v.([]any)
if !ok {
return &func0TypeError{"max", v}
}
return minMaxBy(vs, vs, false)
}
func funcMaxBy(v, x any) any {
vs, ok := v.([]any)
if !ok {
return &func1TypeError{"max_by", v, x}
}
xs, ok := x.([]any)
if !ok {
return &func1TypeError{"max_by", v, x}
}
if len(vs) != len(xs) {
return &func1WrapError{"max_by", v, x, &lengthMismatchError{}}
}
return minMaxBy(vs, xs, false)
}
func minMaxBy(vs, xs []any, isMin bool) any {
if len(vs) == 0 {
return nil
}
i, j, x := 0, 0, xs[0]
for i++; i < len(xs); i++ {
if Compare(x, xs[i]) > 0 == isMin {
j, x = i, xs[i]
}
}
return vs[j]
}
type sortItem struct {
value, key any
}
func sortItems(name string, v, x any) ([]*sortItem, error) {
vs, ok := v.([]any)
if !ok {
if strings.HasSuffix(name, "_by") {
return nil, &func1TypeError{name, v, x}
}
return nil, &func0TypeError{name, v}
}
xs, ok := x.([]any)
if !ok {
return nil, &func1TypeError{name, v, x}
}
if len(vs) != len(xs) {
return nil, &func1WrapError{name, v, x, &lengthMismatchError{}}
}
items := make([]*sortItem, len(vs))
for i, v := range vs {
items[i] = &sortItem{v, xs[i]}
}
sort.SliceStable(items, func(i, j int) bool {
return Compare(items[i].key, items[j].key) < 0
})
return items, nil
}
func funcSort(v any) any {
return sortBy("sort", v, v)
}
func funcSortBy(v, x any) any {
return sortBy("sort_by", v, x)
}
func sortBy(name string, v, x any) any {
items, err := sortItems(name, v, x)
if err != nil {
return err
}
rs := make([]any, len(items))
for i, x := range items {
rs[i] = x.value
}
return rs
}
func funcGroupBy(v, x any) any {
items, err := sortItems("group_by", v, x)
if err != nil {
return err
}
rs := []any{}
var last any
for i, r := range items {
if i == 0 || Compare(last, r.key) != 0 {
rs, last = append(rs, []any{r.value}), r.key
} else {
rs[len(rs)-1] = append(rs[len(rs)-1].([]any), r.value)
}
}
return rs
}
func funcUnique(v any) any {
return uniqueBy("unique", v, v)
}
func funcUniqueBy(v, x any) any {
return uniqueBy("unique_by", v, x)
}
func uniqueBy(name string, v, x any) any {
items, err := sortItems(name, v, x)
if err != nil {
return err
}
rs := []any{}
var last any
for i, r := range items {
if i == 0 || Compare(last, r.key) != 0 {
rs, last = append(rs, r.value), r.key
}
}
return rs
}
func funcSignificand(v float64) float64 {
frac, _ := math.Frexp(v)
return frac * 2
}
func funcExp10(v float64) float64 {
return math.Pow(10, v)
}
func funcFrexp(v any) any {
x, ok := toFloat(v)
if !ok {
return &func0TypeError{"frexp", v}
}
f, e := math.Frexp(x)
return []any{f, e}
}
func funcModf(v any) any {
x, ok := toFloat(v)
if !ok {
return &func0TypeError{"modf", v}
}
if math.IsInf(x, 0) {
return []any{math.Copysign(0, x), x}
}
i, f := math.Modf(x)
return []any{f, i}
}
func funcLgamma(v float64) float64 {
v, _ = math.Lgamma(v)
return v
}
func funcDrem(l, r float64) float64 {
x := math.Remainder(l, r)
if x == 0.0 {
return math.Copysign(x, l)
}
return x
}
func funcFmax(l, r float64) float64 {
if math.IsNaN(l) {
return r
}
if math.IsNaN(r) {
return l
}
return max(l, r)
}
func funcFmin(l, r float64) float64 {
if math.IsNaN(l) {
return r
}
if math.IsNaN(r) {
return l
}
return min(l, r)
}
func funcJn(l, r float64) float64 {
return math.Jn(int(l), r)
}
func funcLdexp(l, r float64) float64 {
return math.Ldexp(l, int(r))
}
func funcYn(l, r float64) float64 {
return math.Yn(int(l), r)
}
func funcInfinite(any) any {
return math.Inf(1)
}
func funcIsfinite(v any) any {
x, ok := toFloat(v)
return ok && !math.IsInf(x, 0)
}
func funcIsinfinite(v any) any {
x, ok := toFloat(v)
return ok && math.IsInf(x, 0)
}
func funcNan(any) any {
return math.NaN()
}
func funcIsnan(v any) any {
x, ok := toFloat(v)
if !ok {
if v == nil {
return false
}
return &func0TypeError{"isnan", v}
}
return math.IsNaN(x)
}
func funcIsnormal(v any) any {
if v, ok := toFloat(v); ok {
e := (math.Float64bits(v) & 0x7ff0000000000000) >> 52
return 0 < e && e < 0x7ff
}
return false
}
// An `allocator` creates new maps and slices, stores the allocated addresses.
// This allocator is used to reduce allocations on assignment operator (`=`),
// update-assignment operator (`|=`), and the `map_values`, `del`, `delpaths`
// functions.
type allocator map[uintptr]struct{}
func funcAllocator(any, []any) any {
return allocator{}
}
func (a allocator) allocated(v any) bool {
_, ok := a[reflect.ValueOf(v).Pointer()]
return ok
}
func (a allocator) makeObject(l int) map[string]any {
v := make(map[string]any, l)
if a != nil {
a[reflect.ValueOf(v).Pointer()] = struct{}{}
}
return v
}
func (a allocator) makeArray(l, c int) []any {
v := make([]any, l, max(l, c))
if a != nil {
a[reflect.ValueOf(v).Pointer()] = struct{}{}
}
return v
}
func funcSetpath(v, p, n any) any {
// There is no need to use an allocator on a single update.
return setpath(v, p, n, nil)
}
// Used in compiler#compileAssign and compiler#compileModify.
func funcSetpathWithAllocator(v any, args []any) any {
return setpath(v, args[0], args[1], args[2].(allocator))
}
func setpath(v, p, n any, a allocator) any {
path, ok := p.([]any)
if !ok {
return &func1TypeError{"setpath", v, p}
}
u, err := update(v, path, n, a)
if err != nil {
return &func2WrapError{"setpath", v, p, n, err}
}
return u
}
func funcDelpaths(v, p any) any {
return delpaths(v, p, allocator{})
}
// Used in compiler#compileAssign and compiler#compileModify.
func funcDelpathsWithAllocator(v any, args []any) any {
return delpaths(v, args[0], args[1].(allocator))
}
func delpaths(v, p any, a allocator) any {
paths, ok := p.([]any)
if !ok {
return &func1TypeError{"delpaths", v, p}
}
if len(paths) == 0 {
return v
}
// Fills the paths with an empty value and then delete them. We cannot delete
// in each loop because array indices should not change. For example,
// jq -n "[0, 1, 2, 3] | delpaths([[1], [2]])" #=> [0, 3].
var empty struct{}
var err error
u := v
for _, q := range paths {
path, ok := q.([]any)
if !ok {
return &func1WrapError{"delpaths", v, p, &expectedArrayError{q}}
}
u, err = update(u, path, empty, a)
if err != nil {
return &func1WrapError{"delpaths", v, p, err}
}
}
return deleteEmpty(u)
}
func update(v any, path []any, n any, a allocator) (any, error) {
if len(path) == 0 {
return n, nil
}
switch p := path[0].(type) {
case string:
switch v := v.(type) {
case nil:
return updateObject(nil, p, path[1:], n, a)
case map[string]any:
return updateObject(v, p, path[1:], n, a)
case struct{}:
return v, nil
default:
return nil, &expectedObjectError{v}
}
case int, float64, *big.Int, json.Number:
i, _ := toInt(p)
switch v := v.(type) {
case nil:
return updateArrayIndex(nil, i, path[1:], n, a)
case []any:
return updateArrayIndex(v, i, path[1:], n, a)
case struct{}:
return v, nil
default:
return nil, &expectedArrayError{v}
}
case map[string]any:
switch v := v.(type) {
case nil:
return updateArraySlice(nil, p, path[1:], n, a)
case []any:
return updateArraySlice(v, p, path[1:], n, a)
case struct{}:
return v, nil
default:
return nil, &expectedArrayError{v}
}
default:
switch v.(type) {
case []any:
return nil, &arrayIndexNotNumberError{p}
default:
return nil, &objectKeyNotStringError{p}
}
}
}
func updateObject(v map[string]any, k string, path []any, n any, a allocator) (any, error) {
x, ok := v[k]
if !ok && n == struct{}{} {
if v == nil {
return nil, nil
}
return v, nil
}
u, err := update(x, path, n, a)
if err != nil {
return nil, err
}
if a.allocated(v) {
v[k] = u
return v, nil
}
w := a.makeObject(len(v) + 1)
maps.Copy(w, v)
w[k] = u
return w, nil
}
func updateArrayIndex(v []any, i int, path []any, n any, a allocator) (any, error) {
var x any
if j := clampIndex(i, -1, len(v)); j < 0 {
if n == struct{}{} {
if v == nil {
return nil, nil
}
return v, nil
}
return nil, &arrayIndexNegativeError{i}
} else if j < len(v) {
i = j
x = v[i]
} else {
if n == struct{}{} {
if v == nil {
return nil, nil
}
return v, nil
}
if i >= 0x20000000 {
return nil, &arrayIndexTooLargeError{i}
}
}
u, err := update(x, path, n, a)
if err != nil {
return nil, err
}
l, c := len(v), cap(v)
if a.allocated(v) {
if i < c {
if i >= l {
v = v[:i+1]
}
v[i] = u
return v, nil
}
c *= 2
}
if i >= l {
l = i + 1
}
w := a.makeArray(l, c)
copy(w, v)
w[i] = u
return w, nil
}
func updateArraySlice(v []any, m map[string]any, path []any, n any, a allocator) (any, error) {
s, ok := m["start"]
if !ok {
return nil, &expectedStartEndError{m}
}
e, ok := m["end"]
if !ok {
return nil, &expectedStartEndError{m}
}
var start, end int
if s != nil {
if i, ok := toInt(s); ok {
start = clampIndex(i, 0, len(v))
} else {
return nil, &arrayIndexNotNumberError{s}
}
}
if e != nil {
if i, ok := toIntCeil(e); ok {
end = clampIndex(i, start, len(v))
} else {
return nil, &arrayIndexNotNumberError{e}
}
} else {
end = len(v)
}
if start == end && n == struct{}{} {
if v == nil {
return nil, nil
}
return v, nil
}
u, err := update(v[start:end], path, n, a)
if err != nil {
return nil, err
}
switch u := u.(type) {
case []any:
var w []any
if len(u) == end-start && a.allocated(v) {
w = v
} else {
w = a.makeArray(len(v)-(end-start)+len(u), 0)
copy(w, v[:start])
copy(w[start+len(u):], v[end:])
}
copy(w[start:], u)
return w, nil
case struct{}:
var w []any
if a.allocated(v) {
w = v
} else {
w = a.makeArray(len(v), 0)
copy(w, v)
}
for i := start; i < end; i++ {
w[i] = u
}
return w, nil
default:
return nil, &expectedArrayError{u}
}
}
func deleteEmpty(v any) any {
switch v := v.(type) {
case struct{}:
return nil
case map[string]any:
for k, w := range v {
if w == struct{}{} {
delete(v, k)
} else {
v[k] = deleteEmpty(w)
}
}
return v
case []any:
var j int
for _, w := range v {
if w != struct{}{} {
v[j] = deleteEmpty(w)
j++
}
}
for i := j; i < len(v); i++ {
v[i] = nil
}
return v[:j]
default:
return v
}
}
func funcGetpath(v, p any) any {
path, ok := p.([]any)
if !ok {
return &func1TypeError{"getpath", v, p}
}
u := v
for _, x := range path {
switch v.(type) {
case nil, []any, map[string]any:
v = funcIndex2(nil, v, x)
if err, ok := v.(error); ok {
return &func1WrapError{"getpath", u, p, err}
}
default:
return &func1TypeError{"getpath", u, p}
}
}
return v
}
func funcTranspose(v any) any {
vss, ok := v.([]any)
if !ok {
return &func0TypeError{"transpose", v}
}
if len(vss) == 0 {
return []any{}
}
var l int
for _, vs := range vss {
vs, ok := vs.([]any)
if !ok {
return &func0TypeError{"transpose", v}
}
if k := len(vs); l < k {
l = k
}
}
wss := make([][]any, l)
xs := make([]any, l)
for i, k := 0, len(vss); i < l; i++ {
s := make([]any, k)
wss[i] = s
xs[i] = s
}
for i, vs := range vss {
for j, v := range vs.([]any) {
wss[j][i] = v
}
}
return xs
}
func funcBsearch(v, t any) any {
vs, ok := v.([]any)
if !ok {
return &func1TypeError{"bsearch", v, t}
}
i := sort.Search(len(vs), func(i int) bool {
return Compare(vs[i], t) >= 0
})
if i < len(vs) && Compare(vs[i], t) == 0 {
return i
}
return -i - 1
}
func funcGmtime(v any) any {
if v, ok := toFloat(v); ok {
return epochToArray(v, time.UTC)
}
return &func0TypeError{"gmtime", v}
}
func funcLocaltime(v any) any {
if v, ok := toFloat(v); ok {
return epochToArray(v, time.Local)
}
return &func0TypeError{"localtime", v}
}
func epochToArray(v float64, loc *time.Location) []any {
t := time.Unix(int64(v), int64((v-math.Floor(v))*1e9)).In(loc)
return []any{
t.Year(),
int(t.Month()) - 1,
t.Day(),
t.Hour(),
t.Minute(),
float64(t.Second()) + float64(t.Nanosecond())/1e9,
int(t.Weekday()),
t.YearDay() - 1,
}
}
func funcMktime(v any) any {
a, ok := v.([]any)
if !ok {
return &func0TypeError{"mktime", v}
}
t, err := arrayToTime(a, time.UTC)
if err != nil {
return &func0WrapError{"mktime", v, err}
}
return timeToEpoch(t)
}
func timeToEpoch(t time.Time) float64 {
return float64(t.Unix()) + float64(t.Nanosecond())/1e9
}
func funcStrftime(v, x any) any {
if w, ok := toFloat(v); ok {
v = epochToArray(w, time.UTC)
}
a, ok := v.([]any)
if !ok {
return &func1TypeError{"strftime", v, x}
}
format, ok := x.(string)
if !ok {
return &func1TypeError{"strftime", v, x}
}
t, err := arrayToTime(a, time.UTC)
if err != nil {
return &func1WrapError{"strftime", v, x, err}
}
return timefmt.Format(t, format)
}
func funcStrflocaltime(v, x any) any {
if w, ok := toFloat(v); ok {
v = epochToArray(w, time.Local)
}
a, ok := v.([]any)
if !ok {
return &func1TypeError{"strflocaltime", v, x}
}
format, ok := x.(string)
if !ok {
return &func1TypeError{"strflocaltime", v, x}
}
t, err := arrayToTime(a, time.Local)
if err != nil {
return &func1WrapError{"strflocaltime", v, x, err}
}
return timefmt.Format(t, format)
}
func funcStrptime(v, x any) any {
s, ok := v.(string)
if !ok {
return &func1TypeError{"strptime", v, x}
}
format, ok := x.(string)
if !ok {
return &func1TypeError{"strptime", v, x}
}
t, err := timefmt.Parse(s, format)
if err != nil {
return &func1WrapError{"strptime", v, x, err}
}
if t.Equal(time.Time{}) {
return &func1TypeError{"strptime", v, x}
}
return epochToArray(timeToEpoch(t), time.UTC)
}
func arrayToTime(a []any, loc *time.Location) (time.Time, error) {
var t time.Time
var year, month, day, hour, minute,
second, nanosecond, weekday, yearday int
for i, p := range []*int{
&year, &month, &day, &hour, &minute,
&second, &weekday, &yearday,
} {
if i >= len(a) {
break
}
if i == 5 {
if v, ok := toFloat(a[i]); ok {
*p = int(v)
nanosecond = int((v - math.Floor(v)) * 1e9)
} else {
return t, &timeArrayError{}
}
} else if v, ok := toInt(a[i]); ok {
*p = v
} else {
return t, &timeArrayError{}
}
}
return time.Date(year, time.Month(month+1), day,
hour, minute, second, nanosecond, loc), nil
}
func funcNow(any) any {
return timeToEpoch(time.Now())
}
func funcMatch(v, re, fs, testing any, cache *sync.Map) any {
var name string
if testing == true {
name = "test"
} else {
name = "match"
}
var flags string
if fs != nil {
var ok bool
flags, ok = fs.(string)
if !ok {
return &func2TypeError{name, v, re, fs}
}
}
s, ok := v.(string)
if !ok {
return &func2TypeError{name, v, re, fs}
}
restr, ok := re.(string)
if !ok {
return &func2TypeError{name, v, re, fs}
}
r, err := compileRegexp(restr, flags, cache)
if err != nil {
return err
}
if testing == true {
return r.MatchString(s)
}
var n int
if strings.ContainsRune(flags, 'g') {
n = -1
} else {
n = 1
}
xs := r.FindAllStringSubmatchIndex(s, n)
res, names := make([]any, len(xs)), r.SubexpNames()
for i, x := range xs {
captures := make([]any, (len(x)-2)/2)
for j := 1; j < len(x)/2; j++ {
var name any
if n := names[j]; n != "" {
name = n
}
if x[j*2] < 0 {
captures[j-1] = map[string]any{
"name": name,
"offset": -1,
"length": 0,
"string": nil,
}
continue
}
captures[j-1] = map[string]any{
"name": name,
"offset": len([]rune(s[:x[j*2]])),
"length": len([]rune(s[:x[j*2+1]])) - len([]rune(s[:x[j*2]])),
"string": s[x[j*2]:x[j*2+1]],
}
}
res[i] = map[string]any{
"offset": len([]rune(s[:x[0]])),
"length": len([]rune(s[:x[1]])) - len([]rune(s[:x[0]])),
"string": s[x[0]:x[1]],
"captures": captures,
}
}
return res
}
func compileRegexp(re, flags string, cache *sync.Map) (*regexp.Regexp, error) {
key := [2]string{re, flags}
if r, ok := cache.Load(key); ok {
return r.(*regexp.Regexp), nil
}
if strings.IndexFunc(flags, func(r rune) bool {
return r != 'g' && r != 'i' && r != 'm'
}) >= 0 {
return nil, fmt.Errorf("unsupported regular expression flag: %q", flags)
}
if strings.ContainsRune(flags, 'i') {
re = "(?i)" + re
}
if strings.ContainsRune(flags, 'm') {
re = "(?s)" + re
}
r, err := regexp.Compile(re)
if err != nil {
return nil, fmt.Errorf("invalid regular expression %q: %s", re, err)
}
cache.Store(key, r)
return r, nil
}
func funcCaptures(v any) any {
captures, ok := v.([]any)
if !ok {
return &expectedArrayError{v}
}
w := make(map[string]any, len(captures))
for _, capture := range captures {
if capture, ok := capture.(map[string]any); ok {
if name, ok := capture["name"].(string); ok {
w[name] = capture["string"]
}
}
}
return w
}
func funcError(v any, args []any) any {
if len(args) > 0 {
v = args[0]
}
return &exitCodeError{v, 5}
}
func funcHalt(any) any {
return &HaltError{nil, 0}
}
func funcHaltError(v any, args []any) any {
code := 5
if len(args) > 0 {
var ok bool
if code, ok = toInt(args[0]); !ok {
return &func0TypeError{"halt_error", args[0]}
}
}
return &HaltError{v, code}
}
func toInt(x any) (int, bool) {
switch x := x.(type) {
case int:
return x, true
case float64:
return floatToInt(x), true
case *big.Int:
if x.IsInt64() {
if i := x.Int64(); math.MinInt <= i && i <= math.MaxInt {
return int(i), true
}
}
if x.Sign() > 0 {
return math.MaxInt, true
}
return math.MinInt, true
case json.Number:
return toInt(parseNumber(x))
default:
return 0, false
}
}
func toIntCeil(x any) (int, bool) {
if f, ok := x.(float64); ok {
x = math.Ceil(f)
}
return toInt(x)
}
func floatToInt(x float64) int {
if math.MinInt <= x && x < math.MaxInt {
return int(x)
}
if x > 0 {
return math.MaxInt
}
return math.MinInt
}
func toFloat(x any) (float64, bool) {
switch x := x.(type) {
case int:
return float64(x), true
case float64:
return x, true
case *big.Int:
return bigToFloat(x), true
case json.Number:
v, err := x.Float64()
return v, err == nil
default:
return 0.0, false
}
}
func bigToFloat(x *big.Int) float64 {
if x.IsInt64() {
return float64(x.Int64())
}
if f, err := strconv.ParseFloat(x.String(), 64); err == nil {
return f
}
return math.Inf(x.Sign())
}
func parseNumber(v json.Number) any {
if i, err := v.Int64(); err == nil && math.MinInt <= i && i <= math.MaxInt {
return int(i)
}
if strings.ContainsAny(v.String(), ".eE") {
if f, err := v.Float64(); err == nil {
return f
}
}
if bi, ok := new(big.Int).SetString(v.String(), 10); ok {
return bi
}
if strings.HasPrefix(v.String(), "-") {
return math.Inf(-1)
}
return math.Inf(1)
}