mirror of
https://github.com/open-cluster-management-io/ocm.git
synced 2026-08-23 22:26:49 +00:00
🌱 Bump github.com/itchyny/gojq from 0.12.18 to 0.12.19 (#1472)
Bumps [github.com/itchyny/gojq](https://github.com/itchyny/gojq) from 0.12.18 to 0.12.19. - [Release notes](https://github.com/itchyny/gojq/releases) - [Changelog](https://github.com/itchyny/gojq/blob/main/CHANGELOG.md) - [Commits](https://github.com/itchyny/gojq/compare/v0.12.18...v0.12.19) --- updated-dependencies: - dependency-name: github.com/itchyny/gojq dependency-version: 0.12.19 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
@@ -14,7 +14,7 @@ require (
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/google/cel-go v0.28.0
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/itchyny/gojq v0.12.18
|
||||
github.com/itchyny/gojq v0.12.19
|
||||
github.com/onsi/ginkgo/v2 v2.28.1
|
||||
github.com/onsi/gomega v1.39.1
|
||||
github.com/openshift/api v0.0.0-20251125174858-5cf710f68a92
|
||||
@@ -129,7 +129,7 @@ require (
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
|
||||
github.com/huandu/xstrings v1.5.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/itchyny/timefmt-go v0.1.7 // indirect
|
||||
github.com/itchyny/timefmt-go v0.1.8 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
|
||||
@@ -266,10 +266,10 @@ github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/itchyny/gojq v0.12.18 h1:gFGHyt/MLbG9n6dqnvlliiya2TaMMh6FFaR2b1H6Drc=
|
||||
github.com/itchyny/gojq v0.12.18/go.mod h1:4hPoZ/3lN9fDL1D+aK7DY1f39XZpY9+1Xpjz8atrEkg=
|
||||
github.com/itchyny/timefmt-go v0.1.7 h1:xyftit9Tbw+Dc/huSSPJaEmX1TVL8lw5vxjJLK4GMMA=
|
||||
github.com/itchyny/timefmt-go v0.1.7/go.mod h1:5E46Q+zj7vbTgWY8o5YkMeYb4I6GeWLFnetPy5oBrAI=
|
||||
github.com/itchyny/gojq v0.12.19 h1:ttXA0XCLEMoaLOz5lSeFOZ6u6Q3QxmG46vfgI4O0DEs=
|
||||
github.com/itchyny/gojq v0.12.19/go.mod h1:5galtVPDywX8SPSOrqjGxkBeDhSxEW1gSxoy7tn1iZY=
|
||||
github.com/itchyny/timefmt-go v0.1.8 h1:1YEo1JvfXeAHKdjelbYr/uCuhkybaHCeTkH8Bo791OI=
|
||||
github.com/itchyny/timefmt-go v0.1.8/go.mod h1:5E46Q+zj7vbTgWY8o5YkMeYb4I6GeWLFnetPy5oBrAI=
|
||||
github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg=
|
||||
github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
||||
github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I=
|
||||
|
||||
+15
@@ -1,4 +1,19 @@
|
||||
# Changelog
|
||||
## [v0.12.19](https://github.com/itchyny/gojq/compare/v0.12.18..v0.12.19) (2026-04-01)
|
||||
* fix `gsub` and `sub` when the replacement emits multiple values
|
||||
* fix `fmax`, `fmin`, `modf` functions against NaN and infinities
|
||||
* fix `join/1` to use `add/0` implementation and handle null separator
|
||||
* fix `del` and `delpaths` on null to emit null
|
||||
* fix arithmetic operations on the minimum integer
|
||||
* fix `significand` function against subnormal numbers
|
||||
* fix handling of `--` in cli flag parsing for jq compatibility
|
||||
* fix `flatten/1` to emit error when the depth is NaN
|
||||
* fix array slice update to validate index types
|
||||
* fix string repetition boundary check to match jq behavior
|
||||
* implement `splits/2` using `match/2` for better jq compatibility
|
||||
* implement `to_entries` and `from_entries` in jq for simplicity
|
||||
* improve performance of regexp functions by caching compiled regexps
|
||||
|
||||
## [v0.12.18](https://github.com/itchyny/gojq/compare/v0.12.17..v0.12.18) (2025-12-02)
|
||||
* implement `trimstr/1`, `toboolean/0` function
|
||||
* fix `last/1` to be included in `builtins/0`
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.25 AS builder
|
||||
FROM golang:1.26 AS builder
|
||||
|
||||
WORKDIR /app
|
||||
COPY go.* ./
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2019-2025 itchyny
|
||||
Copyright (c) 2019-2026 itchyny
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
+1
-1
@@ -75,7 +75,7 @@ lint: $(GOBIN)/staticcheck
|
||||
staticcheck -checks all -tags gojq_debug ./...
|
||||
|
||||
$(GOBIN)/staticcheck:
|
||||
go install honnef.co/go/tools/cmd/staticcheck@latest
|
||||
go install honnef.co/go/tools/cmd/staticcheck@v0.6.1
|
||||
|
||||
.PHONY: check-tools
|
||||
check-tools:
|
||||
|
||||
+5
@@ -56,6 +56,11 @@ gojq: invalid json: <stdin>
|
||||
brew install gojq
|
||||
```
|
||||
|
||||
### mise
|
||||
```sh
|
||||
mise use -g gojq@latest
|
||||
```
|
||||
|
||||
### Zero Install
|
||||
```sh
|
||||
0install add gojq https://apps.0install.net/utils/gojq.xml
|
||||
|
||||
+6
-4
@@ -15,11 +15,12 @@ func init() {
|
||||
"any": {{Name: "any", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "any", Args: []*Query{{Term: &Term{Type: TermTypeIdentity}}}}}}}, {Name: "any", Args: []string{"y"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "any", Args: []*Query{{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{{Iter: true}}}}, {Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "y"}}}}}}}}, {Name: "any", Args: []string{"g", "y"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "isempty", Args: []*Query{{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "g"}}}, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "y"}}}}}}}, Op: OpPipe}}}}}, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "not"}}}, Op: OpPipe}}},
|
||||
"arrays": {{Name: "arrays", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "type"}}}, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "array"}}}, Op: OpEq}}}}}}},
|
||||
"booleans": {{Name: "booleans", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "type"}}}, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "boolean"}}}, Op: OpEq}}}}}}},
|
||||
"capture": {{Name: "capture", Args: []string{"$re"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "capture", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$re"}}}, {Term: &Term{Type: TermTypeNull}}}}}}}, {Name: "capture", Args: []string{"$re", "$flags"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "match", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$re"}}}, {Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$flags"}}}}}}}, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_capture"}}}, Op: OpPipe}}},
|
||||
"capture": {{Name: "capture", Args: []string{"$re"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "capture", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$re"}}}, {Term: &Term{Type: TermTypeNull}}}}}}}, {Name: "capture", Args: []string{"$re", "$flags"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "match", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$re"}}}, {Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$flags"}}}}}}}, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "captures"}}}, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_captures"}}}, Op: OpPipe}, Op: OpPipe}}},
|
||||
"combinations": {{Name: "combinations", Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "length"}}}, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}, Op: OpEq}, Then: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{}}}, Else: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, SuffixList: []*Suffix{{Iter: true}}}}, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$x"}}}}}}, Right: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}, IsSlice: true}}}, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "combinations"}}}, Op: OpPipe}}}, Op: OpAdd}, Patterns: []*Pattern{{Name: "$x"}}, Op: OpPipe}}}}}, {Name: "combinations", Args: []string{"n"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "limit", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "n"}}}, {Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "repeat", Args: []*Query{{Term: &Term{Type: TermTypeIdentity}}}}}}}}}}}}}, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "combinations"}}}, Op: OpPipe}}},
|
||||
"del": {{Name: "del", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "delpaths", Args: []*Query{{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "path", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "f"}}}}}}}}}}}}}}}},
|
||||
"finites": {{Name: "finites", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "isfinite"}}}}}}}}},
|
||||
"first": {{Name: "first", Body: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}}, {Name: "first", Args: []string{"g"}, Body: &Query{Term: &Term{Type: TermTypeLabel, Label: &Label{Ident: "$out", Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "g"}}}, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeIdentity}}, Right: &Query{Term: &Term{Type: TermTypeBreak, Break: "$out"}}, Op: OpComma}, Op: OpPipe}}}}}},
|
||||
"from_entries": {{Name: "from_entries", Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "map", Args: []*Query{{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{{KeyQuery: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "key"}}}, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "Key"}}}, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "name"}}}, Right: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "Name"}}}, Op: OpAlt}, Op: OpAlt}, Op: OpAlt}, Val: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "has", Args: []*Query{{Term: &Term{Type: TermTypeString, Str: &String{Str: "value"}}}}}}}, Then: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "value"}}}, Else: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "Value"}}}}}}}}}}}}}}}, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "add"}}}, Right: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{}}}, Op: OpAlt}, Op: OpPipe}}},
|
||||
"fromdate": {{Name: "fromdate", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "fromdateiso8601"}}}}},
|
||||
"fromdateiso8601": {{Name: "fromdateiso8601", Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "strptime", Args: []*Query{{Term: &Term{Type: TermTypeString, Str: &String{Str: "%Y-%m-%dT%H:%M:%S%z"}}}}}}}, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "mktime"}}}, Op: OpPipe}}},
|
||||
"fromstream": {{Name: "fromstream", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeForeach, Foreach: &Foreach{Query: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "f"}}}, Pattern: &Pattern{Name: "$pv"}, Start: &Query{Term: &Term{Type: TermTypeNull}}, Update: &Query{Left: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "e"}}}, Then: &Query{Term: &Term{Type: TermTypeNull}}}}}, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$pv"}}}, Right: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$pv"}}}, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "length"}}}, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "2"}}, Op: OpEq}, Op: OpPipe}, Then: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "setpath", Args: []*Query{{Left: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "v"}}}}}}, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$p"}}}, Op: OpAdd}, {Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$v"}}}}}}}, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "setpath", Args: []*Query{{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "e"}}}}}}, {Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$p"}}}, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "length"}}}, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}, Op: OpEq}, Op: OpPipe}}}}}, Op: OpPipe}, Else: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "setpath", Args: []*Query{{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "e"}}}}}}, {Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$p"}}}, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "length"}}}, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}, Op: OpEq}, Op: OpPipe}}}}}}}}, Patterns: []*Pattern{{Array: []*Pattern{{Name: "$p"}, {Name: "$v"}}}}, Op: OpPipe}, Op: OpPipe}, Extract: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "e"}}}, Then: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "v"}}}, Else: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "empty"}}}}}}}}}}},
|
||||
@@ -27,7 +28,6 @@ func init() {
|
||||
"gsub": {{Name: "gsub", Args: []string{"$re", "str"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "sub", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$re"}}}, {Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "str"}}}, {Term: &Term{Type: TermTypeString, Str: &String{Str: "g"}}}}}}}}, {Name: "gsub", Args: []string{"$re", "str", "$flags"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "sub", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$re"}}}, {Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "str"}}}, {Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$flags"}}}, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "g"}}}, Op: OpAdd}}}}}}},
|
||||
"in": {{Name: "in", Args: []string{"xs"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeIdentity}}, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "xs"}}}, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "has", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$x"}}}}}}}, Op: OpPipe}, Patterns: []*Pattern{{Name: "$x"}}, Op: OpPipe}}},
|
||||
"inputs": {{Name: "inputs", Body: &Query{Term: &Term{Type: TermTypeTry, Try: &Try{Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "repeat", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "input"}}}}}}}, Catch: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Term: &Term{Type: TermTypeIdentity}}, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "break"}}}, Op: OpEq}, Then: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "empty"}}}, Else: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "error"}}}}}}}}}}},
|
||||
"inside": {{Name: "inside", Args: []string{"xs"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeIdentity}}, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "xs"}}}, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "contains", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$x"}}}}}}}, Op: OpPipe}, Patterns: []*Pattern{{Name: "$x"}}, Op: OpPipe}}},
|
||||
"isempty": {{Name: "isempty", Args: []string{"g"}, Body: &Query{Term: &Term{Type: TermTypeLabel, Label: &Label{Ident: "$out", Body: &Query{Left: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "g"}}}, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFalse}}, Right: &Query{Term: &Term{Type: TermTypeBreak, Break: "$out"}}, Op: OpComma}, Op: OpPipe}}}, Right: &Query{Term: &Term{Type: TermTypeTrue}}, Op: OpComma}}}}}},
|
||||
"iterables": {{Name: "iterables", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "type"}}}, Right: &Query{Left: &Query{Left: &Query{Term: &Term{Type: TermTypeIdentity}}, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "array"}}}, Op: OpEq}, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeIdentity}}, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "object"}}}, Op: OpEq}, Op: OpOr}, Op: OpPipe}}}}}}},
|
||||
"last": {{Name: "last", Body: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeUnary, Unary: &Unary{Op: OpSub, Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}}}}, {Name: "last", Args: []string{"g"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_last", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "g"}}}}}}}}},
|
||||
@@ -53,10 +53,12 @@ func init() {
|
||||
"select": {{Name: "select", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "f"}}}, Then: &Query{Term: &Term{Type: TermTypeIdentity}}, Else: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "empty"}}}}}}}},
|
||||
"skip": {{Name: "skip", Args: []string{"$n", "g"}, Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$n"}}}, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}, Op: OpGt}, Then: &Query{Term: &Term{Type: TermTypeForeach, Foreach: &Foreach{Query: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "g"}}}, Pattern: &Pattern{Name: "$item"}, Start: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$n"}}}, Update: &Query{Left: &Query{Term: &Term{Type: TermTypeIdentity}}, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}, Op: OpSub}, Extract: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Term: &Term{Type: TermTypeIdentity}}, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}, Op: OpLt}, Then: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$item"}}}, Else: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "empty"}}}}}}}}}, Elif: []*IfElif{{Cond: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$n"}}}, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}, Op: OpEq}, Then: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "g"}}}}}, Else: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "error", Args: []*Query{{Term: &Term{Type: TermTypeString, Str: &String{Str: "skip doesn't support negative count"}}}}}}}}}}}},
|
||||
"sort_by": {{Name: "sort_by", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_sort_by", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "map", Args: []*Query{{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "f"}}}}}}}}}}}}}}}},
|
||||
"splits": {{Name: "splits", Args: []string{"$re"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "splits", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$re"}}}, {Term: &Term{Type: TermTypeNull}}}}}}}, {Name: "splits", Args: []string{"$re", "$flags"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "split", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$re"}}}, {Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$flags"}}}}}, SuffixList: []*Suffix{{Iter: true}}}}}},
|
||||
"split": {{Name: "split", Args: []string{"$re", "$flags"}, Body: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "splits", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$re"}}}, {Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$flags"}}}}}}}}}}}},
|
||||
"splits": {{Name: "splits", Args: []string{"$re", "$flags"}, Body: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeForeach, Foreach: &Foreach{Query: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "match", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$re"}}}, {Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$flags"}}}, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "g"}}}, Op: OpAdd}}}}}, Right: &Query{Term: &Term{Type: TermTypeNull}}, Op: OpComma}}}, Pattern: &Pattern{Object: []*PatternObject{{Key: "$offset"}, {Key: "$length"}}}, Start: &Query{Term: &Term{Type: TermTypeNull}}, Update: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{{Key: "start", Val: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "next"}}}}, {Key: "end", Val: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$offset"}}}}, {Key: "next", Val: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$offset"}}}, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$length"}}}, Op: OpAdd}}}}}}}}}}}}}, {Name: "splits", Args: []string{"$re"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "splits", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$re"}}}, {Term: &Term{Type: TermTypeNull}}}}}}}},
|
||||
"strings": {{Name: "strings", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "type"}}}, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "string"}}}, Op: OpEq}}}}}}},
|
||||
"sub": {{Name: "sub", Args: []string{"$re", "str"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "sub", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$re"}}}, {Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "str"}}}, {Term: &Term{Type: TermTypeNull}}}}}}}, {Name: "sub", Args: []string{"$re", "str", "$flags"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeIdentity}}, Right: &Query{FuncDefs: []*FuncDef{{Name: "_sub", Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "matches"}}}, Right: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{}}}, Op: OpEq}, Then: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$str"}, SuffixList: []*Suffix{{Index: &Index{End: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "offset"}}}, IsSlice: true}}}}}, Right: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "string"}}}, Op: OpAdd}, Else: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "matches"}, SuffixList: []*Suffix{{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeUnary, Unary: &Unary{Op: OpSub, Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}}}}}, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{{Key: "string", Val: &Query{Left: &Query{Left: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$r"}}}, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_capture"}}}, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "str"}}}, Op: OpPipe}, Op: OpPipe}}}, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$str"}, SuffixList: []*Suffix{{Index: &Index{Start: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$r"}, SuffixList: []*Suffix{{Index: &Index{Name: "offset"}}}}}, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$r"}, SuffixList: []*Suffix{{Index: &Index{Name: "length"}}}}}, Op: OpAdd}, End: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "offset"}}}, IsSlice: true}}}}}, Op: OpAdd}, Right: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "string"}}}, Op: OpAdd}}, {Key: "offset", Val: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$r"}, SuffixList: []*Suffix{{Index: &Index{Name: "offset"}}}}}}, {Key: "matches", Val: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "matches"}, SuffixList: []*Suffix{{Index: &Index{End: &Query{Term: &Term{Type: TermTypeUnary, Unary: &Unary{Op: OpSub, Term: &Term{Type: TermTypeNumber, Number: "1"}}}}, IsSlice: true}}}}}}}}}}, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_sub"}}}, Op: OpPipe}, Patterns: []*Pattern{{Name: "$r"}}, Op: OpPipe}}}}}}, Left: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{{Key: "string", Val: &Query{Term: &Term{Type: TermTypeString, Str: &String{}}}}, {Key: "matches", Val: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "match", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$re"}}}, {Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$flags"}}}}}}}}}}}}}}}, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_sub"}}}, Op: OpPipe}, Patterns: []*Pattern{{Name: "$str"}}, Op: OpPipe}}},
|
||||
"sub": {{Name: "sub", Args: []string{"$re", "str"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "sub", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$re"}}}, {Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "str"}}}, {Term: &Term{Type: TermTypeNull}}}}}}}, {Name: "sub", Args: []string{"$re", "str", "$flags"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeReduce, Reduce: &Reduce{Query: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "match", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$re"}}}, {Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$flags"}}}}}}}, Pattern: &Pattern{Object: []*PatternObject{{Key: "$offset"}, {Key: "$length"}, {Key: "$captures"}}}, Start: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{{Key: "s", Val: &Query{Term: &Term{Type: TermTypeIdentity}}}, {Key: "r", Val: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{}}}}}}}}, Update: &Query{Left: &Query{Term: &Term{Type: TermTypeReduce, Reduce: &Reduce{Query: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$captures"}}}, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_captures"}}}, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "str"}}}, Op: OpPipe}, Op: OpPipe}}}, Pattern: &Pattern{Name: "$s"}, Start: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "i"}}}, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}, Op: OpAssign}, Update: &Query{Left: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "r"}, SuffixList: []*Suffix{{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "i"}}}}}}}}, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "s"}, SuffixList: []*Suffix{{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "next"}}}, End: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$offset"}}}, IsSlice: true}}}}}, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$s"}}}, Op: OpAdd}, Op: OpUpdateAdd}, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "i"}}}, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}, Op: OpUpdateAdd}, Op: OpPipe}}}}, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "next"}}}, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$offset"}}}, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$length"}}}, Op: OpAdd}, Op: OpAssign}, Op: OpPipe}}}}, Right: &Query{Left: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "r"}, SuffixList: []*Suffix{{Iter: true}}}}, Right: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "s"}, SuffixList: []*Suffix{{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "next"}}}, IsSlice: true}}}}}, Op: OpAdd}, Right: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "s"}}}, Op: OpAlt}, Op: OpPipe}}},
|
||||
"test": {{Name: "test", Args: []string{"$re"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "test", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$re"}}}, {Term: &Term{Type: TermTypeNull}}}}}}}, {Name: "test", Args: []string{"$re", "$flags"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_match", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$re"}}}, {Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$flags"}}}, {Term: &Term{Type: TermTypeTrue}}}}}}}},
|
||||
"to_entries": {{Name: "to_entries", Body: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "keys"}, SuffixList: []*Suffix{{Iter: true}}}}, Right: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{{Key: "key", Val: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$k"}}}}, {Key: "value", Val: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$k"}}}}}}}}}}}, Patterns: []*Pattern{{Name: "$k"}}, Op: OpPipe}}}}}},
|
||||
"todate": {{Name: "todate", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "todateiso8601"}}}}},
|
||||
"todateiso8601": {{Name: "todateiso8601", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "strftime", Args: []*Query{{Term: &Term{Type: TermTypeString, Str: &String{Str: "%Y-%m-%dT%H:%M:%SZ"}}}}}}}}},
|
||||
"tostream": {{Name: "tostream", Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "path", Args: []*Query{{FuncDefs: []*FuncDef{{Name: "r", Body: &Query{Left: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{{Iter: true}, {Optional: true}}}}, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "r"}}}, Op: OpPipe}}}, Right: &Query{Term: &Term{Type: TermTypeIdentity}}, Op: OpComma}}}, Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "r"}}}}}}}, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "getpath", Args: []*Query{{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$p"}}}}}}}, Right: &Query{Term: &Term{Type: TermTypeReduce, Reduce: &Reduce{Query: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "path", Args: []*Query{{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{{Iter: true}, {Optional: true}}}}}}}}, Pattern: &Pattern{Name: "$q"}, Start: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$p"}}}, Right: &Query{Term: &Term{Type: TermTypeIdentity}}, Op: OpComma}}}}, Update: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$p"}}}, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$q"}}}, Op: OpAdd}}}}}}}, Op: OpPipe}, Patterns: []*Pattern{{Name: "$p"}}, Op: OpPipe}}},
|
||||
|
||||
+22
-22
@@ -1,12 +1,19 @@
|
||||
def not: if . then false else true end;
|
||||
def in(xs): . as $x | xs | has($x);
|
||||
def map(f): [.[] | f];
|
||||
def with_entries(f): to_entries | map(f) | from_entries;
|
||||
def add(f): [f] | add;
|
||||
def map_values(f): .[] |= f;
|
||||
def in(xs): . as $x | xs | has($x);
|
||||
def not: if . then false else true end;
|
||||
def select(f): if f then . else empty end;
|
||||
|
||||
def recurse: recurse(.[]?);
|
||||
def recurse(f): def r: ., (f | r); r;
|
||||
def recurse(f; cond): def r: ., (f | select(cond) | r); r;
|
||||
|
||||
def to_entries: [keys[] as $k | {key: $k, value: .[$k]}];
|
||||
def from_entries: map({ (.key // .Key // .name // .Name):
|
||||
if has("value") then .value else .Value end }) | add // {};
|
||||
def with_entries(f): to_entries | map(f) | from_entries;
|
||||
|
||||
def while(cond; update):
|
||||
def _while: if cond then ., (update | _while) else empty end;
|
||||
_while;
|
||||
@@ -20,7 +27,6 @@ def range($end): _range(0; $end; 1);
|
||||
def range($start; $end): _range($start; $end; 1);
|
||||
def range($start; $end; $step): _range($start; $end; $step);
|
||||
|
||||
def add(f): [f] | add;
|
||||
def min_by(f): _min_by(map([f]));
|
||||
def max_by(f): _max_by(map([f]));
|
||||
def sort_by(f): _sort_by(map([f]));
|
||||
@@ -39,7 +45,6 @@ def nulls: select(. == null);
|
||||
def values: select(. != null);
|
||||
def scalars: select(type | . != "array" and . != "object");
|
||||
|
||||
def inside(xs): . as $x | xs | contains($x);
|
||||
def combinations:
|
||||
if length == 0 then
|
||||
[]
|
||||
@@ -47,6 +52,7 @@ def combinations:
|
||||
.[0][] as $x | [$x] + (.[1:] | combinations)
|
||||
end;
|
||||
def combinations(n): [limit(n; repeat(.))] | combinations;
|
||||
|
||||
def walk(f):
|
||||
def _walk:
|
||||
if type == "array" then
|
||||
@@ -67,6 +73,7 @@ def all(g; y): isempty(g | select(y | not));
|
||||
def any: any(.);
|
||||
def any(y): any(.[]; y);
|
||||
def any(g; y): isempty(g | select(y)) | not;
|
||||
|
||||
def limit($n; g):
|
||||
if $n > 0 then
|
||||
label $out |
|
||||
@@ -121,7 +128,6 @@ def tostream:
|
||||
getpath($p) |
|
||||
reduce path(.[]?) as $q ([$p, .]; [$p + $q]);
|
||||
|
||||
def map_values(f): .[] |= f;
|
||||
def del(f): delpaths([path(f)]);
|
||||
def paths: path(..) | select(. != []);
|
||||
def paths(f): path(.. | select(f)) | select(. != []);
|
||||
@@ -138,7 +144,7 @@ def match($re; $flags): _match($re; $flags; false)[];
|
||||
def test($re): test($re; null);
|
||||
def test($re; $flags): _match($re; $flags; true);
|
||||
def capture($re): capture($re; null);
|
||||
def capture($re; $flags): match($re; $flags) | _capture;
|
||||
def capture($re; $flags): match($re; $flags) | .captures | _captures;
|
||||
def scan($re): scan($re; null);
|
||||
def scan($re; $flags):
|
||||
match($re; $flags + "g") |
|
||||
@@ -147,24 +153,18 @@ def scan($re; $flags):
|
||||
else
|
||||
[.captures[].string]
|
||||
end;
|
||||
def splits($re; $flags):
|
||||
.[foreach (match($re; $flags + "g"), null) as {$offset, $length}
|
||||
(null; {start: .next, end: $offset, next: $offset + $length})];
|
||||
def splits($re): splits($re; null);
|
||||
def splits($re; $flags): split($re; $flags)[];
|
||||
def split($re; $flags): [splits($re; $flags)];
|
||||
def sub($re; str): sub($re; str; null);
|
||||
def sub($re; str; $flags):
|
||||
. as $str |
|
||||
def _sub:
|
||||
if .matches == [] then
|
||||
$str[:.offset] + .string
|
||||
else
|
||||
.matches[-1] as $r |
|
||||
{
|
||||
string: ($r | _capture | str) + $str[$r.offset+$r.length:.offset] + .string,
|
||||
offset: $r.offset,
|
||||
matches: .matches[:-1],
|
||||
} |
|
||||
_sub
|
||||
end;
|
||||
{ string: "", matches: [match($re; $flags)] } | _sub;
|
||||
reduce match($re; $flags) as {$offset, $length, $captures}
|
||||
({s: ., r: []};
|
||||
reduce ($captures | _captures | str) as $s
|
||||
(.i = 0; .r[.i] += .s[.next:$offset] + $s | .i += 1) |
|
||||
.next = $offset + $length) | .r[] + .s[.next:] // .s;
|
||||
def gsub($re; str): sub($re; str; "g");
|
||||
def gsub($re; str; $flags): sub($re; str; $flags + "g");
|
||||
|
||||
|
||||
+5
-1
@@ -15,7 +15,7 @@ func Compare(l, r any) int {
|
||||
cmp.Compare,
|
||||
func(l, r float64) int {
|
||||
switch {
|
||||
case l < r || math.IsNaN(l):
|
||||
case lt(l, r):
|
||||
return -1
|
||||
case l == r:
|
||||
return 0
|
||||
@@ -51,6 +51,10 @@ func Compare(l, r any) int {
|
||||
)
|
||||
}
|
||||
|
||||
func lt(l, r float64) bool {
|
||||
return l < r || math.IsNaN(l)
|
||||
}
|
||||
|
||||
func typeIndex(v any) int {
|
||||
switch v := v.(type) {
|
||||
default:
|
||||
|
||||
+13
@@ -7,6 +7,7 @@ import (
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type compiler struct {
|
||||
@@ -20,6 +21,7 @@ type compiler struct {
|
||||
builtinScope *scopeinfo
|
||||
scopes []*scopeinfo
|
||||
scopecnt int
|
||||
regexpCache sync.Map
|
||||
}
|
||||
|
||||
// Code is a compiled jq query.
|
||||
@@ -996,6 +998,13 @@ func (c *compiler) compileFunc(e *Func) error {
|
||||
c.append(&code{op: opbacktrack})
|
||||
setfork()
|
||||
return nil
|
||||
case "_match":
|
||||
return c.compileCallInternal(
|
||||
[3]any{c.funcMatch, len(e.Args), e.Name},
|
||||
e.Args,
|
||||
true,
|
||||
-1,
|
||||
)
|
||||
default:
|
||||
return c.compileCall(e.Name, e.Args)
|
||||
}
|
||||
@@ -1279,6 +1288,10 @@ func listModuleDeps(q *Query) []any {
|
||||
return deps
|
||||
}
|
||||
|
||||
func (c *compiler) funcMatch(v any, args []any) any {
|
||||
return funcMatch(v, args[0], args[1], args[2], &c.regexpCache)
|
||||
}
|
||||
|
||||
func (c *compiler) compileObject(e *Object) error {
|
||||
c.appendCodeInfo(e)
|
||||
if len(e.KeyVals) == 0 {
|
||||
|
||||
-8
@@ -221,14 +221,6 @@ func (err *flattenDepthError) Error() string {
|
||||
return "flatten depth should not be negative: " + Preview(err.v)
|
||||
}
|
||||
|
||||
type joinTypeError struct {
|
||||
v any
|
||||
}
|
||||
|
||||
func (err *joinTypeError) Error() string {
|
||||
return "join cannot be applied to an array including: " + typeErrorPreview(err.v)
|
||||
}
|
||||
|
||||
type timeArrayError struct{}
|
||||
|
||||
func (*timeArrayError) Error() string {
|
||||
|
||||
+129
-158
@@ -6,15 +6,18 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"iter"
|
||||
"maps"
|
||||
"math"
|
||||
"math/big"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
@@ -58,8 +61,6 @@ func init() {
|
||||
"utf8bytelength": argFunc0(funcUtf8ByteLength),
|
||||
"keys": argFunc0(funcKeys),
|
||||
"has": argFunc1(funcHas),
|
||||
"to_entries": argFunc0(funcToEntries),
|
||||
"from_entries": argFunc0(funcFromEntries),
|
||||
"add": argFunc0(funcAdd),
|
||||
"toboolean": argFunc0(funcToBoolean),
|
||||
"tonumber": argFunc0(funcToNumber),
|
||||
@@ -67,6 +68,7 @@ func init() {
|
||||
"type": argFunc0(funcType),
|
||||
"reverse": argFunc0(funcReverse),
|
||||
"contains": argFunc1(funcContains),
|
||||
"inside": argFunc1(funcInside),
|
||||
"indices": argFunc1(funcIndices),
|
||||
"index": argFunc1(funcIndex),
|
||||
"rindex": argFunc1(funcRindex),
|
||||
@@ -80,7 +82,8 @@ func init() {
|
||||
"trim": argFunc0(funcTrim),
|
||||
"explode": argFunc0(funcExplode),
|
||||
"implode": argFunc0(funcImplode),
|
||||
"split": {argcount1 | argcount2, false, funcSplit},
|
||||
"split": argFunc1(funcSplit),
|
||||
"join": argFunc1(funcJoin),
|
||||
"ascii_downcase": argFunc0(funcASCIIDowncase),
|
||||
"ascii_upcase": argFunc0(funcASCIIUpcase),
|
||||
"tojson": argFunc0(funcToJSON),
|
||||
@@ -121,7 +124,6 @@ func init() {
|
||||
"_group_by": argFunc1(funcGroupBy),
|
||||
"unique": argFunc0(funcUnique),
|
||||
"_unique_by": argFunc1(funcUniqueBy),
|
||||
"join": argFunc1(funcJoin),
|
||||
"sin": mathFunc("sin", math.Sin),
|
||||
"cos": mathFunc("cos", math.Cos),
|
||||
"tan": mathFunc("tan", math.Tan),
|
||||
@@ -168,8 +170,8 @@ func init() {
|
||||
"copysign": mathFunc2("copysign", math.Copysign),
|
||||
"drem": mathFunc2("drem", funcDrem),
|
||||
"fdim": mathFunc2("fdim", math.Dim),
|
||||
"fmax": mathFunc2("fmax", math.Max),
|
||||
"fmin": mathFunc2("fmin", math.Min),
|
||||
"fmax": mathFunc2("fmax", funcFmax),
|
||||
"fmin": mathFunc2("fmin", funcFmin),
|
||||
"fmod": mathFunc2("fmod", math.Mod),
|
||||
"hypot": mathFunc2("hypot", math.Hypot),
|
||||
"jn": mathFunc2("jn", funcJn),
|
||||
@@ -200,8 +202,8 @@ func init() {
|
||||
"strflocaltime": argFunc1(funcStrflocaltime),
|
||||
"strptime": argFunc1(funcStrptime),
|
||||
"now": argFunc0(funcNow),
|
||||
"_match": argFunc3(funcMatch),
|
||||
"_capture": argFunc0(funcCapture),
|
||||
"_match": argFunc3(nil),
|
||||
"_captures": argFunc0(funcCaptures),
|
||||
"error": {argcount0 | argcount1, false, funcError},
|
||||
"halt": argFunc0(funcHalt),
|
||||
"halt_error": {argcount0 | argcount1, false, funcHaltError},
|
||||
@@ -288,7 +290,7 @@ func funcAbs(v any) any {
|
||||
if v >= 0 {
|
||||
return v
|
||||
}
|
||||
return -v
|
||||
return negate(v)
|
||||
case float64:
|
||||
return math.Abs(v)
|
||||
case *big.Int:
|
||||
@@ -314,7 +316,7 @@ func funcLength(v any) any {
|
||||
if v >= 0 {
|
||||
return v
|
||||
}
|
||||
return -v
|
||||
return negate(v)
|
||||
case float64:
|
||||
return math.Abs(v)
|
||||
case *big.Int:
|
||||
@@ -408,70 +410,17 @@ func funcHas(v, x any) any {
|
||||
return &func1TypeError{"has", v, x}
|
||||
}
|
||||
|
||||
func funcToEntries(v any) any {
|
||||
switch v := v.(type) {
|
||||
case []any:
|
||||
w := make([]any, len(v))
|
||||
for i, x := range v {
|
||||
w[i] = map[string]any{"key": i, "value": x}
|
||||
}
|
||||
return w
|
||||
case map[string]any:
|
||||
w := make([]any, len(v))
|
||||
for i, k := range keys(v) {
|
||||
w[i] = map[string]any{"key": k, "value": v[k]}
|
||||
}
|
||||
return w
|
||||
default:
|
||||
return &func0TypeError{"to_entries", v}
|
||||
}
|
||||
}
|
||||
|
||||
func funcFromEntries(v any) any {
|
||||
vs, ok := v.([]any)
|
||||
if !ok {
|
||||
return &func0TypeError{"from_entries", v}
|
||||
}
|
||||
w := make(map[string]any, len(vs))
|
||||
for _, v := range vs {
|
||||
switch v := v.(type) {
|
||||
case map[string]any:
|
||||
var (
|
||||
key string
|
||||
value any
|
||||
ok bool
|
||||
)
|
||||
for _, k := range [4]string{"key", "Key", "name", "Name"} {
|
||||
if k := v[k]; k != nil && k != false {
|
||||
if key, ok = k.(string); !ok {
|
||||
return &func0WrapError{"from_entries", vs, &objectKeyNotStringError{k}}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
return &func0WrapError{"from_entries", vs, &objectKeyNotStringError{nil}}
|
||||
}
|
||||
for _, k := range [2]string{"value", "Value"} {
|
||||
if value, ok = v[k]; ok {
|
||||
break
|
||||
}
|
||||
}
|
||||
w[key] = value
|
||||
default:
|
||||
return &func0TypeError{"from_entries", v}
|
||||
}
|
||||
}
|
||||
return w
|
||||
}
|
||||
|
||||
func funcAdd(v any) any {
|
||||
vs, ok := values(v)
|
||||
if !ok {
|
||||
return &func0TypeError{"add", v}
|
||||
}
|
||||
v = nil
|
||||
for _, x := range vs {
|
||||
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
|
||||
@@ -618,6 +567,10 @@ func funcContains(v, x any) any {
|
||||
)
|
||||
}
|
||||
|
||||
func funcInside(v, x any) any {
|
||||
return funcContains(x, v)
|
||||
}
|
||||
|
||||
func funcIndices(v, x any) any {
|
||||
return indexFunc("indices", v, x, indices)
|
||||
}
|
||||
@@ -807,33 +760,16 @@ func funcImplode(v any) any {
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func funcSplit(v any, args []any) any {
|
||||
func funcSplit(v, x any) any {
|
||||
s, ok := v.(string)
|
||||
if !ok {
|
||||
return &func0TypeError{"split", v}
|
||||
}
|
||||
x, ok := args[0].(string)
|
||||
t, ok := x.(string)
|
||||
if !ok {
|
||||
return &func0TypeError{"split", x}
|
||||
}
|
||||
var ss []string
|
||||
if len(args) == 1 {
|
||||
ss = strings.Split(s, x)
|
||||
} else {
|
||||
var flags string
|
||||
if args[1] != nil {
|
||||
v, ok := args[1].(string)
|
||||
if !ok {
|
||||
return &func0TypeError{"split", args[1]}
|
||||
}
|
||||
flags = v
|
||||
}
|
||||
r, err := compileRegexp(x, flags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ss = r.Split(s, -1)
|
||||
}
|
||||
ss := strings.Split(s, t)
|
||||
xs := make([]any, len(ss))
|
||||
for i, s := range ss {
|
||||
xs[i] = s
|
||||
@@ -841,6 +777,34 @@ func funcSplit(v any, args []any) any {
|
||||
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 {
|
||||
@@ -1203,7 +1167,7 @@ func funcFlatten(v any, args []any) any {
|
||||
if !ok {
|
||||
return &func0TypeError{"flatten", args[0]}
|
||||
}
|
||||
if depth < 0 {
|
||||
if lt(depth, 0) {
|
||||
return &flattenDepthError{depth}
|
||||
}
|
||||
}
|
||||
@@ -1393,44 +1357,9 @@ func uniqueBy(name string, v, x any) any {
|
||||
return rs
|
||||
}
|
||||
|
||||
func funcJoin(v, x any) any {
|
||||
vs, ok := values(v)
|
||||
if !ok {
|
||||
return &func1TypeError{"join", v, x}
|
||||
}
|
||||
if len(vs) == 0 {
|
||||
return ""
|
||||
}
|
||||
sep, ok := x.(string)
|
||||
if len(vs) > 1 && !ok {
|
||||
return &func1TypeError{"join", v, x}
|
||||
}
|
||||
ss := make([]string, len(vs))
|
||||
for i, v := range vs {
|
||||
switch v := v.(type) {
|
||||
case nil:
|
||||
case string:
|
||||
ss[i] = v
|
||||
case bool:
|
||||
if v {
|
||||
ss[i] = "true"
|
||||
} else {
|
||||
ss[i] = "false"
|
||||
}
|
||||
case int, float64, *big.Int, json.Number:
|
||||
ss[i] = jsonMarshal(v)
|
||||
default:
|
||||
return &joinTypeError{v}
|
||||
}
|
||||
}
|
||||
return strings.Join(ss, sep)
|
||||
}
|
||||
|
||||
func funcSignificand(v float64) float64 {
|
||||
if math.IsNaN(v) || math.IsInf(v, 0) || v == 0.0 {
|
||||
return v
|
||||
}
|
||||
return math.Float64frombits((math.Float64bits(v) & 0x800fffffffffffff) | 0x3ff0000000000000)
|
||||
frac, _ := math.Frexp(v)
|
||||
return frac * 2
|
||||
}
|
||||
|
||||
func funcExp10(v float64) float64 {
|
||||
@@ -1451,6 +1380,9 @@ func funcModf(v any) any {
|
||||
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}
|
||||
}
|
||||
@@ -1468,6 +1400,26 @@ func funcDrem(l, r float64) float64 {
|
||||
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)
|
||||
}
|
||||
@@ -1511,7 +1463,7 @@ func funcIsnan(v any) any {
|
||||
|
||||
func funcIsnormal(v any) any {
|
||||
if v, ok := toFloat(v); ok {
|
||||
e := math.Float64bits(v) & 0x7ff0000000000000 >> 52
|
||||
e := (math.Float64bits(v) & 0x7ff0000000000000) >> 52
|
||||
return 0 < e && e < 0x7ff
|
||||
}
|
||||
return false
|
||||
@@ -1658,6 +1610,9 @@ func update(v any, path []any, n any, a allocator) (any, error) {
|
||||
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)
|
||||
@@ -1678,6 +1633,9 @@ func updateArrayIndex(v []any, i int, path []any, n any, a allocator) (any, erro
|
||||
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}
|
||||
@@ -1686,6 +1644,9 @@ func updateArrayIndex(v []any, i int, path []any, n any, a allocator) (any, erro
|
||||
x = v[i]
|
||||
} else {
|
||||
if n == struct{}{} {
|
||||
if v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
if i >= 0x20000000 {
|
||||
@@ -1726,15 +1687,26 @@ func updateArraySlice(v []any, m map[string]any, path []any, n any, a allocator)
|
||||
return nil, &expectedStartEndError{m}
|
||||
}
|
||||
var start, end int
|
||||
if i, ok := toInt(s); ok {
|
||||
start = clampIndex(i, 0, len(v))
|
||||
if s != nil {
|
||||
if i, ok := toInt(s); ok {
|
||||
start = clampIndex(i, 0, len(v))
|
||||
} else {
|
||||
return nil, &arrayIndexNotNumberError{s}
|
||||
}
|
||||
}
|
||||
if i, ok := toInt(e); ok {
|
||||
end = clampIndex(i, start, len(v))
|
||||
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)
|
||||
@@ -1962,8 +1934,7 @@ func funcStrptime(v, x any) any {
|
||||
if err != nil {
|
||||
return &func1WrapError{"strptime", v, x, err}
|
||||
}
|
||||
var u time.Time
|
||||
if t == u {
|
||||
if t.Equal(time.Time{}) {
|
||||
return &func1TypeError{"strptime", v, x}
|
||||
}
|
||||
return epochToArray(timeToEpoch(t), time.UTC)
|
||||
@@ -2001,18 +1972,20 @@ func funcNow(any) any {
|
||||
return timeToEpoch(time.Now())
|
||||
}
|
||||
|
||||
func funcMatch(v, re, fs, testing any) any {
|
||||
name := "match"
|
||||
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 {
|
||||
v, ok := fs.(string)
|
||||
var ok bool
|
||||
flags, ok = fs.(string)
|
||||
if !ok {
|
||||
return &func2TypeError{name, v, re, fs}
|
||||
}
|
||||
flags = v
|
||||
}
|
||||
s, ok := v.(string)
|
||||
if !ok {
|
||||
@@ -2022,22 +1995,20 @@ func funcMatch(v, re, fs, testing any) any {
|
||||
if !ok {
|
||||
return &func2TypeError{name, v, re, fs}
|
||||
}
|
||||
r, err := compileRegexp(restr, flags)
|
||||
r, err := compileRegexp(restr, flags, cache)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var xs [][]int
|
||||
if strings.ContainsRune(flags, 'g') && testing != true {
|
||||
xs = r.FindAllStringSubmatchIndex(s, -1)
|
||||
} else {
|
||||
got := r.FindStringSubmatchIndex(s)
|
||||
if testing == true {
|
||||
return got != nil
|
||||
}
|
||||
if got != nil {
|
||||
xs = [][]int{got}
|
||||
}
|
||||
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)
|
||||
@@ -2072,7 +2043,11 @@ func funcMatch(v, re, fs, testing any) any {
|
||||
return res
|
||||
}
|
||||
|
||||
func compileRegexp(re, flags string) (*regexp.Regexp, error) {
|
||||
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 {
|
||||
@@ -2088,15 +2063,11 @@ func compileRegexp(re, flags string) (*regexp.Regexp, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid regular expression %q: %s", re, err)
|
||||
}
|
||||
cache.Store(key, r)
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func funcCapture(v any) any {
|
||||
vs, ok := v.(map[string]any)
|
||||
if !ok {
|
||||
return &expectedObjectError{v}
|
||||
}
|
||||
v = vs["captures"]
|
||||
func funcCaptures(v any) any {
|
||||
captures, ok := v.([]any)
|
||||
if !ok {
|
||||
return &expectedArrayError{v}
|
||||
@@ -2165,7 +2136,7 @@ func toIntCeil(x any) (int, bool) {
|
||||
}
|
||||
|
||||
func floatToInt(x float64) int {
|
||||
if math.MinInt <= x && x <= math.MaxInt {
|
||||
if math.MinInt <= x && x < math.MaxInt {
|
||||
return int(x)
|
||||
}
|
||||
if x > 0 {
|
||||
|
||||
+1
-1
@@ -4,5 +4,5 @@ go 1.24.0
|
||||
|
||||
require (
|
||||
github.com/itchyny/astgen-go v0.0.0-20250520171007-4331c963041e // indirect
|
||||
github.com/itchyny/timefmt-go v0.1.7 // indirect
|
||||
github.com/itchyny/timefmt-go v0.1.8 // indirect
|
||||
)
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
github.com/itchyny/astgen-go v0.0.0-20250520171007-4331c963041e h1:Pu7Ev38D+75aWdsHzULyVZfMP3WrgIHNUaAUH81CTqE=
|
||||
github.com/itchyny/astgen-go v0.0.0-20250520171007-4331c963041e/go.mod h1:8EXgnGrgW1p0qVnOF1A/4ORQEUAi8TvxQdIR+zJfKxM=
|
||||
github.com/itchyny/timefmt-go v0.1.7 h1:xyftit9Tbw+Dc/huSSPJaEmX1TVL8lw5vxjJLK4GMMA=
|
||||
github.com/itchyny/timefmt-go v0.1.7/go.mod h1:5E46Q+zj7vbTgWY8o5YkMeYb4I6GeWLFnetPy5oBrAI=
|
||||
github.com/itchyny/timefmt-go v0.1.8 h1:1YEo1JvfXeAHKdjelbYr/uCuhkybaHCeTkH8Bo791OI=
|
||||
github.com/itchyny/timefmt-go v0.1.8/go.mod h1:5E46Q+zj7vbTgWY8o5YkMeYb4I6GeWLFnetPy5oBrAI=
|
||||
|
||||
+33
-17
@@ -279,10 +279,17 @@ func funcOpPlus(v any) any {
|
||||
}
|
||||
}
|
||||
|
||||
func negate(v int) any {
|
||||
if v == math.MinInt {
|
||||
return new(big.Int).Neg(big.NewInt(int64(v)))
|
||||
}
|
||||
return -v
|
||||
}
|
||||
|
||||
func funcOpNegate(v any) any {
|
||||
switch v := v.(type) {
|
||||
case int:
|
||||
return -v
|
||||
return negate(v)
|
||||
case float64:
|
||||
return -v
|
||||
case *big.Int:
|
||||
@@ -378,6 +385,9 @@ func funcOpSub(_, l, r any) any {
|
||||
func funcOpMul(_, l, r any) any {
|
||||
return binopTypeSwitch(l, r,
|
||||
func(l, r int) any {
|
||||
if r == -1 {
|
||||
return negate(l)
|
||||
}
|
||||
if v := l * r; r == 0 || v/r == l {
|
||||
return v
|
||||
}
|
||||
@@ -422,28 +432,30 @@ func deepMergeObjects(l, r map[string]any) any {
|
||||
}
|
||||
|
||||
func repeatString(s string, n float64) any {
|
||||
if n < 0.0 || math.IsNaN(n) {
|
||||
if lt(n, 0) {
|
||||
return nil
|
||||
}
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
if n >= float64(math.MaxInt32/len(s)) {
|
||||
c := int(min(n, math.MaxInt32))
|
||||
if uint64(len(s))*uint64(c) >= math.MaxInt32 {
|
||||
return &repeatStringTooLargeError{s, n}
|
||||
}
|
||||
return strings.Repeat(s, int(n))
|
||||
return strings.Repeat(s, c)
|
||||
}
|
||||
|
||||
func funcOpDiv(_, l, r any) any {
|
||||
return binopTypeSwitch(l, r,
|
||||
func(l, r int) any {
|
||||
if r == 0 {
|
||||
switch r {
|
||||
case 0:
|
||||
return &zeroDivisionError{l, r}
|
||||
case -1:
|
||||
return negate(l)
|
||||
default:
|
||||
if l%r == 0 {
|
||||
return l / r
|
||||
}
|
||||
return float64(l) / float64(r)
|
||||
}
|
||||
if l%r == 0 {
|
||||
return l / r
|
||||
}
|
||||
return float64(l) / float64(r)
|
||||
},
|
||||
func(l, r float64) any {
|
||||
if r == 0.0 {
|
||||
@@ -481,19 +493,23 @@ func funcOpDiv(_, l, r any) any {
|
||||
func funcOpMod(_, l, r any) any {
|
||||
return binopTypeSwitch(l, r,
|
||||
func(l, r int) any {
|
||||
if r == 0 {
|
||||
switch r {
|
||||
case 0:
|
||||
return &zeroModuloError{l, r}
|
||||
case -1:
|
||||
return 0
|
||||
default:
|
||||
return l % r
|
||||
}
|
||||
return l % r
|
||||
},
|
||||
func(l, r float64) any {
|
||||
if math.IsNaN(l) || math.IsNaN(r) {
|
||||
return math.NaN()
|
||||
}
|
||||
ri := floatToInt(r)
|
||||
if ri == 0 {
|
||||
return &zeroModuloError{l, r}
|
||||
}
|
||||
if math.IsNaN(l) || math.IsNaN(r) {
|
||||
return math.NaN()
|
||||
}
|
||||
return floatToInt(l) % ri
|
||||
},
|
||||
func(l, r *big.Int) any {
|
||||
|
||||
+114
-119
@@ -154,140 +154,135 @@ var yyExca = [...]int16{
|
||||
-1, 1,
|
||||
1, -1,
|
||||
-2, 0,
|
||||
-1, 138,
|
||||
-1, 139,
|
||||
5, 0,
|
||||
-2, 27,
|
||||
-1, 141,
|
||||
-1, 142,
|
||||
7, 0,
|
||||
-2, 30,
|
||||
-1, 198,
|
||||
-1, 194,
|
||||
59, 114,
|
||||
-2, 49,
|
||||
}
|
||||
|
||||
const yyPrivate = 57344
|
||||
|
||||
const yyLast = 781
|
||||
const yyLast = 733
|
||||
|
||||
var yyAct = [...]int16{
|
||||
78, 133, 174, 185, 103, 10, 210, 194, 175, 130,
|
||||
108, 102, 5, 134, 48, 228, 158, 50, 73, 74,
|
||||
123, 6, 32, 93, 73, 74, 243, 14, 110, 246,
|
||||
204, 227, 157, 203, 115, 279, 122, 264, 278, 120,
|
||||
135, 98, 97, 245, 148, 149, 136, 73, 74, 104,
|
||||
179, 180, 181, 226, 114, 242, 73, 74, 179, 180,
|
||||
181, 281, 116, 117, 118, 73, 74, 225, 177, 253,
|
||||
178, 255, 73, 74, 127, 128, 177, 99, 178, 234,
|
||||
237, 207, 233, 240, 206, 131, 230, 162, 229, 160,
|
||||
182, 73, 74, 73, 74, 219, 6, 153, 182, 159,
|
||||
156, 126, 125, 247, 6, 277, 161, 252, 137, 138,
|
||||
139, 140, 141, 142, 143, 144, 145, 146, 151, 150,
|
||||
124, 73, 74, 188, 45, 73, 74, 239, 183, 184,
|
||||
73, 74, 73, 74, 50, 244, 147, 192, 173, 213,
|
||||
91, 195, 92, 272, 168, 73, 74, 76, 199, 200,
|
||||
73, 74, 75, 202, 119, 205, 270, 90, 84, 196,
|
||||
83, 269, 95, 94, 214, 96, 165, 212, 216, 217,
|
||||
209, 190, 218, 80, 81, 129, 84, 82, 83, 43,
|
||||
44, 104, 266, 167, 25, 221, 3, 211, 211, 24,
|
||||
223, 220, 224, 215, 131, 222, 73, 74, 231, 96,
|
||||
85, 86, 87, 88, 89, 236, 176, 232, 238, 47,
|
||||
80, 81, 189, 84, 82, 83, 43, 44, 85, 86,
|
||||
87, 88, 89, 85, 86, 87, 88, 89, 248, 73,
|
||||
74, 250, 251, 195, 186, 187, 249, 101, 254, 87,
|
||||
88, 89, 164, 261, 262, 258, 256, 257, 241, 263,
|
||||
273, 196, 163, 155, 265, 85, 86, 87, 88, 89,
|
||||
267, 268, 84, 82, 83, 121, 271, 211, 211, 193,
|
||||
274, 275, 84, 191, 276, 132, 73, 74, 73, 74,
|
||||
79, 129, 174, 195, 103, 10, 210, 190, 175, 227,
|
||||
135, 32, 5, 158, 102, 108, 48, 93, 6, 123,
|
||||
243, 234, 50, 246, 233, 226, 225, 242, 110, 157,
|
||||
98, 264, 15, 99, 115, 122, 97, 245, 104, 120,
|
||||
224, 148, 149, 114, 37, 21, 22, 23, 33, 207,
|
||||
74, 253, 206, 34, 130, 35, 36, 39, 41, 40,
|
||||
42, 19, 20, 28, 31, 43, 44, 116, 117, 118,
|
||||
240, 229, 228, 92, 127, 160, 133, 29, 30, 159,
|
||||
126, 131, 18, 73, 75, 27, 136, 132, 38, 43,
|
||||
44, 26, 125, 95, 94, 204, 96, 153, 203, 124,
|
||||
156, 252, 198, 45, 239, 186, 161, 151, 74, 96,
|
||||
88, 89, 90, 150, 138, 139, 140, 141, 142, 143,
|
||||
144, 145, 146, 147, 137, 179, 180, 181, 183, 184,
|
||||
43, 44, 77, 188, 179, 180, 181, 191, 199, 50,
|
||||
173, 73, 75, 177, 192, 178, 185, 76, 74, 200,
|
||||
74, 119, 177, 202, 178, 205, 74, 80, 86, 87,
|
||||
88, 89, 90, 266, 214, 182, 91, 212, 216, 217,
|
||||
104, 6, 218, 209, 182, 165, 74, 74, 74, 219,
|
||||
6, 73, 75, 73, 75, 221, 222, 74, 223, 73,
|
||||
75, 134, 211, 211, 230, 74, 255, 281, 215, 3,
|
||||
279, 196, 197, 278, 136, 236, 231, 74, 238, 73,
|
||||
75, 73, 75, 170, 273, 171, 169, 74, 25, 74,
|
||||
73, 75, 74, 24, 237, 220, 162, 247, 73, 75,
|
||||
249, 250, 191, 176, 277, 248, 47, 17, 254, 192,
|
||||
73, 75, 251, 261, 262, 9, 256, 257, 101, 263,
|
||||
73, 75, 73, 75, 265, 73, 75, 259, 260, 78,
|
||||
267, 268, 164, 272, 244, 258, 271, 112, 113, 213,
|
||||
274, 275, 211, 211, 276, 74, 241, 155, 121, 74,
|
||||
280, 52, 53, 54, 55, 56, 57, 58, 59, 60,
|
||||
61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
|
||||
71, 72, 106, 107, 85, 86, 87, 88, 89, 9,
|
||||
43, 44, 259, 260, 85, 86, 87, 88, 89, 170,
|
||||
17, 171, 169, 77, 16, 201, 15, 37, 21, 22,
|
||||
23, 33, 7, 105, 8, 4, 34, 208, 35, 36,
|
||||
71, 72, 106, 107, 189, 187, 128, 201, 73, 75,
|
||||
43, 44, 73, 75, 7, 8, 4, 2, 74, 1,
|
||||
111, 0, 168, 270, 16, 13, 14, 37, 21, 22,
|
||||
23, 33, 0, 105, 13, 0, 34, 208, 35, 36,
|
||||
39, 41, 40, 42, 19, 20, 28, 31, 43, 44,
|
||||
112, 113, 2, 80, 81, 1, 84, 82, 83, 0,
|
||||
29, 30, 0, 166, 0, 18, 0, 0, 27, 0,
|
||||
0, 73, 75, 81, 82, 0, 85, 83, 84, 0,
|
||||
29, 30, 269, 167, 85, 18, 84, 0, 27, 0,
|
||||
154, 38, 0, 152, 26, 52, 53, 54, 55, 56,
|
||||
57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
|
||||
67, 68, 69, 70, 71, 72, 106, 107, 85, 86,
|
||||
87, 88, 89, 0, 43, 44, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 111, 0, 11, 12, 16, 13,
|
||||
15, 37, 21, 22, 23, 33, 0, 105, 13, 0,
|
||||
67, 68, 69, 70, 71, 72, 106, 107, 86, 87,
|
||||
88, 89, 90, 0, 43, 44, 86, 87, 88, 89,
|
||||
90, 0, 74, 0, 0, 0, 11, 12, 16, 0,
|
||||
14, 37, 21, 22, 23, 33, 0, 105, 0, 0,
|
||||
34, 100, 35, 36, 39, 41, 40, 42, 19, 20,
|
||||
28, 31, 43, 44, 0, 0, 0, 0, 80, 81,
|
||||
0, 84, 82, 83, 29, 30, 0, 0, 79, 18,
|
||||
0, 0, 27, 0, 0, 38, 0, 16, 26, 15,
|
||||
28, 31, 43, 44, 0, 73, 75, 0, 81, 82,
|
||||
0, 85, 83, 84, 29, 30, 232, 0, 166, 18,
|
||||
0, 0, 27, 0, 0, 38, 0, 16, 26, 14,
|
||||
37, 21, 22, 23, 33, 0, 0, 0, 0, 34,
|
||||
0, 35, 36, 39, 41, 40, 42, 19, 20, 28,
|
||||
31, 43, 44, 85, 86, 87, 88, 89, 0, 0,
|
||||
0, 0, 0, 29, 30, 0, 0, 0, 18, 0,
|
||||
31, 43, 44, 86, 87, 88, 89, 90, 0, 0,
|
||||
0, 0, 0, 29, 30, 85, 83, 84, 18, 0,
|
||||
0, 27, 0, 0, 38, 0, 235, 26, 16, 0,
|
||||
15, 37, 21, 22, 23, 33, 0, 0, 0, 0,
|
||||
14, 37, 21, 22, 23, 33, 0, 0, 0, 0,
|
||||
34, 0, 35, 36, 39, 41, 40, 42, 19, 20,
|
||||
28, 31, 43, 44, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 29, 30, 0, 0, 0, 18,
|
||||
28, 31, 43, 44, 0, 74, 0, 86, 87, 88,
|
||||
89, 90, 163, 0, 29, 30, 0, 0, 0, 18,
|
||||
0, 0, 27, 0, 0, 38, 0, 109, 26, 16,
|
||||
0, 15, 37, 21, 22, 23, 33, 0, 0, 0,
|
||||
0, 14, 37, 21, 22, 23, 33, 0, 73, 75,
|
||||
0, 34, 0, 35, 36, 39, 41, 40, 42, 19,
|
||||
20, 28, 31, 43, 44, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 29, 30, 0, 0, 0,
|
||||
20, 28, 31, 43, 44, 0, 0, 81, 82, 0,
|
||||
85, 83, 84, 0, 0, 29, 30, 0, 0, 0,
|
||||
18, 0, 0, 27, 0, 0, 38, 0, 0, 26,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
|
||||
62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
|
||||
72, 49, 0, 0, 0, 0, 0, 0, 0, 51,
|
||||
72, 49, 86, 87, 88, 89, 90, 0, 0, 51,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
|
||||
62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
|
||||
72, 49, 0, 0, 0, 0, 172, 0, 0, 51,
|
||||
37, 21, 22, 23, 33, 0, 0, 0, 0, 34,
|
||||
0, 35, 36, 39, 41, 40, 42, 19, 20, 28,
|
||||
31, 43, 44, 0, 0, 0, 46, 0, 0, 0,
|
||||
0, 0, 0, 29, 30, 0, 0, 0, 18, 0,
|
||||
0, 27, 0, 0, 38, 0, 0, 26, 52, 53,
|
||||
54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
64, 65, 66, 67, 68, 69, 70, 71, 72, 106,
|
||||
198, 0, 0, 0, 0, 0, 0, 43, 44, 0,
|
||||
72, 49, 85, 0, 0, 0, 172, 0, 0, 51,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
|
||||
62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
|
||||
72, 106, 194, 0, 0, 0, 46, 0, 0, 43,
|
||||
44, 0, 0, 0, 86, 87, 88, 89, 90, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
197,
|
||||
0, 0, 193,
|
||||
}
|
||||
|
||||
var yyPact = [...]int16{
|
||||
176, -1000, -1000, -42, 405, 66, 642, -1000, -1000, -1000,
|
||||
182, 115, 110, 556, 444, 127, 111, 108, 142, -1000,
|
||||
-1000, -1000, -1000, -1000, 17, -1000, 367, 505, -1000, 664,
|
||||
664, 179, -1000, 556, 664, 664, 664, 124, 556, -1000,
|
||||
-1000, -1000, -1000, -1000, -1000, -1000, -1000, -28, -1000, 61,
|
||||
43, 42, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
|
||||
189, -1000, -1000, -45, 405, 45, 642, -1000, -1000, -1000,
|
||||
94, 110, 95, 556, 127, 593, 137, 39, 52, -1000,
|
||||
-1000, -1000, -1000, -1000, -27, -1000, 367, 505, -1000, 28,
|
||||
28, 93, -1000, 556, 28, 28, 28, 121, 556, -1000,
|
||||
-1000, -1000, -1000, -1000, -1000, -1000, -1000, -29, -1000, 40,
|
||||
33, 21, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
|
||||
-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
|
||||
-1000, -1000, -1000, 556, 556, 161, -42, -1000, 182, -17,
|
||||
664, 664, 664, 664, 664, 664, 664, 664, 664, 664,
|
||||
89, -15, -1000, -1000, -1000, 142, 311, -1000, -1000, 556,
|
||||
-1000, -32, -1000, 40, 30, 556, -1000, -1000, -1000, -1000,
|
||||
25, 556, 108, 108, -1000, 231, 140, 349, 169, -1000,
|
||||
83, 282, -1000, 612, 41, 41, 41, 182, -1000, 205,
|
||||
65, -1000, 165, -1000, -1000, -17, 720, 206, 255, 151,
|
||||
265, 174, 188, 188, -1000, -1000, -1000, 556, 556, 205,
|
||||
-1000, -1000, -1000, -29, 556, 23, 182, -1000, 273, 664,
|
||||
664, 78, -1000, 556, -1000, 664, -17, -17, -1000, -1000,
|
||||
-1000, -1000, -1000, 556, 24, 556, 177, -45, -1000, 94,
|
||||
77, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||
28, -18, -1000, -1000, -1000, 52, 311, -1000, -1000, 556,
|
||||
-1000, -35, -1000, 20, 16, 556, -1000, -1000, -1000, -1000,
|
||||
164, 556, 39, 39, -1000, 531, 149, 444, 349, -1000,
|
||||
261, 176, -1000, 612, 108, 108, 108, 94, 99, -1000,
|
||||
-1000, 24, 672, 163, 172, 44, -1000, 556, 593, 498,
|
||||
357, 665, 109, 59, 59, -1000, -1000, -1000, 556, 172,
|
||||
-1000, -1000, -1000, 36, 556, -9, 94, -1000, 273, 28,
|
||||
28, 208, -1000, 556, -1000, 28, 24, 24, -1000, -1000,
|
||||
-1000, 556, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
|
||||
-1000, -1000, 33, -1000, -1000, -42, -1000, -1000, -1000, 556,
|
||||
-17, 5, -1000, -33, -1000, 29, 27, 556, -1000, 182,
|
||||
149, 21, -1000, -1000, 454, 18, -1000, 556, -1000, -1000,
|
||||
80, 206, 80, 24, 182, -1000, -5, -34, 74, -1000,
|
||||
-19, -1000, 45, 182, -1000, -1000, -17, -1000, 720, -17,
|
||||
-17, 46, -1000, 10, 205, -1000, 9, -1000, 182, 664,
|
||||
664, 290, 556, 556, -1000, -1000, 41, -1000, -1000, -1000,
|
||||
-1000, -1000, -22, 556, -1000, -1000, 80, 80, 158, 556,
|
||||
556, 103, 98, -1000, -17, 85, -1000, 229, 182, 556,
|
||||
556, -1000, -1000, 556, 44, -23, 182, -1000, -1000, 556,
|
||||
0, -1000,
|
||||
-1000, -1000, 117, -1000, -1000, 556, 24, -22, -1000, -39,
|
||||
-1000, 13, 12, 556, -1000, -45, -1000, -1000, -1000, 94,
|
||||
398, -37, -1000, -1000, 454, 162, -1000, 556, -1000, -1000,
|
||||
57, 593, 57, 11, 94, -1000, -33, -40, 203, -1000,
|
||||
-25, -1000, 94, -1000, -1000, 24, -1000, 672, 24, 24,
|
||||
181, 43, -1000, -8, 172, -1000, 134, -1000, 94, 28,
|
||||
28, 235, 556, 556, -1000, -1000, 108, -1000, -1000, -1000,
|
||||
-1000, -28, -1000, 556, -1000, -1000, 57, 57, 139, 556,
|
||||
556, 304, 265, -1000, 24, 205, -1000, 193, 94, 556,
|
||||
556, -1000, -1000, 556, 173, 142, 94, -1000, -1000, 556,
|
||||
136, -1000,
|
||||
}
|
||||
|
||||
var yyPgo = [...]int16{
|
||||
0, 355, 352, 335, 334, 9, 332, 309, 414, 325,
|
||||
0, 275, 1, 273, 269, 7, 27, 320, 22, 265,
|
||||
23, 253, 248, 245, 242, 237, 11, 6, 2, 8,
|
||||
209, 14, 206, 191, 3, 189, 184, 10, 4,
|
||||
0, 319, 317, 316, 315, 10, 314, 245, 320, 307,
|
||||
0, 306, 1, 305, 304, 7, 32, 237, 11, 278,
|
||||
17, 277, 276, 265, 262, 248, 14, 6, 2, 8,
|
||||
236, 16, 233, 225, 3, 223, 218, 15, 4,
|
||||
}
|
||||
|
||||
var yyR1 = [...]int8{
|
||||
@@ -330,31 +325,31 @@ var yyR2 = [...]int8{
|
||||
|
||||
var yyChk = [...]int16{
|
||||
-1000, -1, -2, 10, -3, -29, 63, -6, -4, -7,
|
||||
-10, 11, 12, -8, -16, 15, 13, -17, 54, 33,
|
||||
-10, 11, 12, -8, 15, -16, 13, -17, 54, 33,
|
||||
34, 17, 18, 19, -35, -36, 63, 57, 35, 49,
|
||||
50, 36, -18, 20, 25, 27, 28, 16, 60, 29,
|
||||
31, 30, 32, 37, 38, 58, 64, -30, -31, 29,
|
||||
-37, 37, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
|
||||
26, 27, 28, 47, 48, 37, 37, -7, -10, 14,
|
||||
4, 5, 8, 9, 7, 49, 50, 51, 52, 53,
|
||||
30, 29, 34, -20, 55, 54, 57, -20, -18, 60,
|
||||
26, 27, 28, 47, 14, 48, 37, 37, -7, -10,
|
||||
30, 4, 5, 8, 9, 7, 49, 50, 51, 52,
|
||||
53, 29, 34, -20, 55, 54, 57, -20, -18, 60,
|
||||
64, -25, -26, -38, -18, 60, 29, 30, -37, 62,
|
||||
-10, -8, -17, -17, -18, -10, -16, -16, -16, 30,
|
||||
-10, -19, 64, 48, 59, 59, 59, -10, -10, 14,
|
||||
-5, -29, -11, -12, 30, 57, 63, -16, -16, -16,
|
||||
-16, -16, -16, -16, -16, -16, -16, 47, 59, 60,
|
||||
-10, -19, 64, 48, 59, 59, 59, -10, -11, -12,
|
||||
30, 57, 63, -10, 14, -5, -29, 47, -16, -16,
|
||||
-16, -16, -16, -16, -16, -16, -16, -16, 59, 60,
|
||||
-20, -18, 62, -10, 59, -21, -10, 64, 48, 59,
|
||||
59, -10, 62, 21, -24, 26, 14, 14, 61, 40,
|
||||
37, 39, 64, -31, -28, -29, -32, 35, 37, 17,
|
||||
18, 19, 57, -28, -28, -34, 29, 30, 58, 47,
|
||||
6, -13, -12, -14, -15, -38, -18, 60, 30, -10,
|
||||
18, 19, 57, -28, -28, 47, 6, -13, -12, -14,
|
||||
-15, -38, -18, 60, 30, -34, 29, 30, 58, -10,
|
||||
-10, -9, -34, 62, 59, -10, 61, 58, 64, -26,
|
||||
-27, -16, -27, 61, -10, -16, -12, -12, -10, 62,
|
||||
-33, -28, -5, -10, -12, 62, 48, 64, 48, 59,
|
||||
59, -10, 58, 61, 58, 62, -10, 62, -10, 47,
|
||||
59, -22, 60, 60, 61, 62, 48, 58, -12, -15,
|
||||
-12, -12, 61, 59, -34, 62, -27, -27, -23, 22,
|
||||
-33, -28, -10, -12, 62, 48, 64, 48, 59, 59,
|
||||
-10, -5, 58, 61, 58, 62, -10, 62, -10, 47,
|
||||
59, -22, 60, 60, 61, 62, 48, -12, -15, -12,
|
||||
-12, 61, 58, 59, -34, 62, -27, -27, -23, 22,
|
||||
23, -10, -10, -28, 59, -10, 24, -10, -10, 58,
|
||||
58, -12, 58, 21, -10, -10, -10, 61, 61, 58,
|
||||
-10, 61,
|
||||
@@ -362,31 +357,31 @@ var yyChk = [...]int16{
|
||||
|
||||
var yyDef = [...]int16{
|
||||
2, -2, 4, 0, 12, 0, 0, 1, 5, 10,
|
||||
11, 0, 0, 12, 25, 0, 0, 36, 50, 51,
|
||||
11, 0, 0, 12, 0, 25, 0, 36, 50, 51,
|
||||
52, 55, 56, 57, 58, 60, 0, 0, 66, 0,
|
||||
0, 69, 71, 0, 0, 0, 0, 0, 0, 89,
|
||||
90, 91, 92, 84, 86, 3, 125, 0, 128, 0,
|
||||
0, 0, 137, 138, 139, 140, 141, 142, 143, 144,
|
||||
145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
|
||||
155, 156, 157, 0, 0, 0, 8, 13, 20, 0,
|
||||
155, 156, 157, 0, 0, 0, 0, 8, 13, 20,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 79, 80, 81, 0, 0, 53, 54, 0,
|
||||
61, 0, 106, 111, 112, 0, 113, 114, 115, 64,
|
||||
0, 0, 67, 68, 70, 0, 104, 0, 0, 77,
|
||||
0, 0, 126, 0, 0, 0, 0, 21, 24, 0,
|
||||
0, 9, 0, 37, 39, 0, 0, 26, -2, 28,
|
||||
29, -2, 31, 32, 33, 34, 35, 0, 0, 0,
|
||||
0, 0, 126, 0, 0, 0, 0, 21, 0, 37,
|
||||
39, 0, 0, 24, 0, 0, 9, 0, 26, -2,
|
||||
28, 29, -2, 31, 32, 33, 34, 35, 0, 0,
|
||||
82, 83, 93, 0, 0, 0, 98, 62, 0, 0,
|
||||
0, 0, 65, 0, 73, 0, 0, 0, 78, 85,
|
||||
87, 0, 127, 129, 130, 118, 119, 120, 121, 122,
|
||||
123, 124, 0, 131, 132, 8, 18, 19, 7, 0,
|
||||
0, 0, 42, 0, 44, 0, 0, 0, -2, 23,
|
||||
123, 124, 0, 131, 132, 0, 0, 0, 42, 0,
|
||||
44, 0, 0, 0, -2, 8, 18, 19, 7, 23,
|
||||
0, 0, 16, 94, 0, 0, 59, 0, 63, 107,
|
||||
108, 117, 109, 0, 100, 105, 0, 0, 0, 133,
|
||||
0, 135, 0, 22, 38, 40, 0, 41, 0, 0,
|
||||
0, 135, 22, 38, 40, 0, 41, 0, 0, 0,
|
||||
0, 0, 14, 0, 0, 95, 0, 96, 99, 0,
|
||||
0, 102, 0, 0, 88, 134, 0, 6, 43, 45,
|
||||
46, 47, 0, 0, 17, 97, 116, 110, 0, 0,
|
||||
0, 102, 0, 0, 88, 134, 0, 43, 45, 46,
|
||||
47, 0, 6, 0, 17, 97, 116, 110, 0, 0,
|
||||
0, 0, 0, 136, 0, 0, 72, 0, 103, 0,
|
||||
0, 48, 15, 0, 0, 0, 101, 74, 75, 0,
|
||||
0, 76,
|
||||
|
||||
+8
@@ -1,4 +1,12 @@
|
||||
# Changelog
|
||||
## [v0.1.8](https://github.com/itchyny/timefmt-go/compare/v0.1.7..v0.1.8) (2026-04-01)
|
||||
* fix parsing negative year and Unix time (`%Y`, `%G`, `%s`)
|
||||
* fix formatting negative year, century, Unix time (`%Y`, `%G`, `%C`, `%y`, `%g`, `%s`)
|
||||
* fix `%g` parsing to use the same two-digit year threshold 69 as `%y`
|
||||
* fix `%s` formatting and parsing on 32-bit platforms
|
||||
* support parsing time zone offset with `%:::z`
|
||||
* improve performance of parsing/formatting compound directives
|
||||
|
||||
## [v0.1.7](https://github.com/itchyny/timefmt-go/compare/v0.1.6..v0.1.7) (2025-10-01)
|
||||
* refactor code using built-in `min` and `max` functions
|
||||
|
||||
|
||||
+102
-83
@@ -85,12 +85,20 @@ func AppendFormat(buf []byte, t time.Time, format string) []byte {
|
||||
case 'Y':
|
||||
buf = appendInt(buf, year, or(width, 4), padding)
|
||||
case 'y':
|
||||
buf = appendInt(buf, year%100, max(width, 2), padding)
|
||||
buf = appendInt(buf, abs(year%100), max(width, 2), padding)
|
||||
case 'C':
|
||||
buf = appendInt(buf, year/100, max(width, 2), padding)
|
||||
c := year / 100
|
||||
z := year < 0 && c == 0
|
||||
if z {
|
||||
c = -1
|
||||
}
|
||||
buf = appendInt(buf, c, max(width, 2), padding)
|
||||
if z {
|
||||
buf[len(buf)-1] = '0'
|
||||
}
|
||||
case 'g':
|
||||
year, _ := t.ISOWeek()
|
||||
buf = appendInt(buf, year%100, max(width, 2), padding)
|
||||
buf = appendInt(buf, abs(year%100), max(width, 2), padding)
|
||||
case 'G':
|
||||
year, _ := t.ISOWeek()
|
||||
buf = appendInt(buf, year, or(width, 4), padding)
|
||||
@@ -161,7 +169,7 @@ func AppendFormat(buf []byte, t time.Time, format string) []byte {
|
||||
if padding < ^paddingMask {
|
||||
padding = ' '
|
||||
}
|
||||
buf = appendInt(buf, int(t.Unix()), width, padding)
|
||||
buf = appendInt64(buf, t.Unix(), width, padding)
|
||||
case 'f':
|
||||
buf = appendInt(buf, t.Nanosecond()/1000, or(width, 6), padding)
|
||||
case 'Z', 'z':
|
||||
@@ -237,13 +245,24 @@ func AppendFormat(buf []byte, t time.Time, format string) []byte {
|
||||
buf = appendString(buf, "\n", width, padding, false, false)
|
||||
case '%':
|
||||
buf = appendString(buf, "%", width, padding, false, false)
|
||||
case 'c':
|
||||
pending, swap = "a b e H:M:S Y", false
|
||||
case '+':
|
||||
pending, swap = "a b e H:M:S Z Y", false
|
||||
case 'v':
|
||||
pending, swap = "e-b-Y", false
|
||||
case 'r':
|
||||
pending, swap = "I:M:S p", false
|
||||
case 'F':
|
||||
pending = "Y-m-d"
|
||||
case 'D', 'x':
|
||||
pending = "m/d/y"
|
||||
case 'T', 'X':
|
||||
pending = "H:M:S"
|
||||
case 'R':
|
||||
pending = "H:M"
|
||||
default:
|
||||
if pending == "" {
|
||||
var ok bool
|
||||
if pending, ok = compositions[b]; ok {
|
||||
swap = false
|
||||
break
|
||||
}
|
||||
buf = appendLast(buf, format[:i], width-1, padding)
|
||||
}
|
||||
buf = append(buf, b)
|
||||
@@ -261,73 +280,79 @@ K:
|
||||
return appendLast(buf, format, width, padding)
|
||||
}
|
||||
|
||||
const smalls = "" +
|
||||
"00010203040506070809" +
|
||||
"10111213141516171819" +
|
||||
"20212223242526272829" +
|
||||
"30313233343536373839" +
|
||||
"40414243444546474849" +
|
||||
"50515253545556575859" +
|
||||
"60616263646566676869" +
|
||||
"70717273747576777879" +
|
||||
"80818283848586878889" +
|
||||
"90919293949596979899"
|
||||
|
||||
func appendInt(buf []byte, num, width int, padding byte) []byte {
|
||||
var digits int
|
||||
switch {
|
||||
default:
|
||||
fallthrough
|
||||
case num < 0:
|
||||
return appendInt64(buf, int64(num), width, padding)
|
||||
case num < 100 && width == 2 && padding == '0':
|
||||
return append(buf, smalls[num*2:num*2+2]...)
|
||||
case num < 10:
|
||||
digits = 1
|
||||
case num < 100:
|
||||
digits = 2
|
||||
case num < 1000:
|
||||
digits = 3
|
||||
case num < 10000:
|
||||
digits = 4
|
||||
}
|
||||
if padding != ^paddingMask {
|
||||
padding &= paddingMask
|
||||
switch width {
|
||||
case 2:
|
||||
if num < 10 {
|
||||
buf = append(buf, padding)
|
||||
goto L1
|
||||
} else if num < 100 {
|
||||
goto L2
|
||||
} else if num < 1000 {
|
||||
goto L3
|
||||
} else if num < 10000 {
|
||||
goto L4
|
||||
}
|
||||
case 4:
|
||||
if num < 1000 {
|
||||
buf = append(buf, padding)
|
||||
if num < 100 {
|
||||
buf = append(buf, padding)
|
||||
if num < 10 {
|
||||
buf = append(buf, padding)
|
||||
goto L1
|
||||
}
|
||||
goto L2
|
||||
}
|
||||
goto L3
|
||||
} else if num < 10000 {
|
||||
goto L4
|
||||
}
|
||||
default:
|
||||
i := len(buf)
|
||||
for ; width > 1; width-- {
|
||||
buf = append(buf, padding)
|
||||
}
|
||||
j := len(buf)
|
||||
buf = strconv.AppendInt(buf, int64(num), 10)
|
||||
if k := min(len(buf)-j-1, j-i); k > 0 {
|
||||
copy(buf[j-k:], buf[j:])
|
||||
buf = buf[:len(buf)-k]
|
||||
}
|
||||
return buf
|
||||
for ; width > digits; width-- {
|
||||
buf = append(buf, padding)
|
||||
}
|
||||
}
|
||||
if num < 100 {
|
||||
if num < 10 {
|
||||
goto L1
|
||||
}
|
||||
goto L2
|
||||
} else if num < 10000 {
|
||||
if num < 1000 {
|
||||
goto L3
|
||||
}
|
||||
goto L4
|
||||
switch digits {
|
||||
case 4:
|
||||
buf = append(buf, byte(num/1000)|'0')
|
||||
num %= 1000
|
||||
fallthrough
|
||||
case 3:
|
||||
buf = append(buf, byte(num/100)|'0')
|
||||
num %= 100
|
||||
fallthrough
|
||||
case 2:
|
||||
buf = append(buf, byte(num/10)|'0')
|
||||
num %= 10
|
||||
fallthrough
|
||||
default:
|
||||
return append(buf, byte(num)|'0')
|
||||
}
|
||||
return strconv.AppendInt(buf, int64(num), 10)
|
||||
L4:
|
||||
buf = append(buf, byte(num/1000)|'0')
|
||||
num %= 1000
|
||||
L3:
|
||||
buf = append(buf, byte(num/100)|'0')
|
||||
num %= 100
|
||||
L2:
|
||||
buf = append(buf, byte(num/10)|'0')
|
||||
num %= 10
|
||||
L1:
|
||||
return append(buf, byte(num)|'0')
|
||||
}
|
||||
|
||||
func appendInt64(buf []byte, num int64, width int, padding byte) []byte {
|
||||
if padding == ^paddingMask {
|
||||
return strconv.AppendInt(buf, num, 10)
|
||||
}
|
||||
padding &= paddingMask
|
||||
i := len(buf)
|
||||
for ; width > 1; width-- {
|
||||
buf = append(buf, padding)
|
||||
}
|
||||
j := len(buf)
|
||||
buf = strconv.AppendInt(buf, num, 10)
|
||||
if k := min(len(buf)-j-1, j-i); k > 0 {
|
||||
copy(buf[j-k:], buf[j:])
|
||||
buf = buf[:len(buf)-k]
|
||||
if j -= k; buf[i] == '0' && buf[j] == '-' {
|
||||
buf[i], buf[j] = '-', '0'
|
||||
}
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
func appendString(buf []byte, str string, width int, padding byte, upper, swap bool) []byte {
|
||||
@@ -377,6 +402,13 @@ func or(x, y int) int {
|
||||
return y
|
||||
}
|
||||
|
||||
func abs(x int) int {
|
||||
if x >= 0 {
|
||||
return x
|
||||
}
|
||||
return -x
|
||||
}
|
||||
|
||||
const paddingMask byte = 0x7F
|
||||
|
||||
var longMonthNames = []string{
|
||||
@@ -428,16 +460,3 @@ var shortWeekNames = []string{
|
||||
"Fri",
|
||||
"Sat",
|
||||
}
|
||||
|
||||
var compositions = map[byte]string{
|
||||
'c': "a b e H:M:S Y",
|
||||
'+': "a b e H:M:S Z Y",
|
||||
'F': "Y-m-d",
|
||||
'D': "m/d/y",
|
||||
'x': "m/d/y",
|
||||
'v': "e-b-Y",
|
||||
'T': "H:M:S",
|
||||
'X': "H:M:S",
|
||||
'r': "I:M:S p",
|
||||
'R': "H:M",
|
||||
}
|
||||
|
||||
+94
-55
@@ -3,7 +3,6 @@ package timefmt
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -25,26 +24,33 @@ func parse(source, format string, loc, base *time.Location) (t time.Time, err er
|
||||
err = fmt.Errorf("failed to parse %q with %q: %w", source, format, err)
|
||||
}
|
||||
}()
|
||||
var j, week, weekday, yday, colons int
|
||||
var j, week, weekday, yday, colons, sign int
|
||||
century, weekstart := -1, time.Weekday(-1)
|
||||
var pm, hasISOYear, hasZoneName, hasZoneOffset bool
|
||||
var pending string
|
||||
for i, l := 0, len(source); i < len(format); i++ {
|
||||
if b := format[i]; b == '%' {
|
||||
i++
|
||||
if i == len(format) {
|
||||
if i++; i == len(format) {
|
||||
err = errors.New(`stray "%"`)
|
||||
return
|
||||
}
|
||||
b = format[i]
|
||||
L:
|
||||
switch b {
|
||||
case 'G':
|
||||
hasISOYear = true
|
||||
fallthrough
|
||||
case 'Y':
|
||||
if year, j, err = parseNumber(source, j, 4, 0, 9999, 'Y'); err != nil {
|
||||
sign, j = parseSign(source, j, l)
|
||||
if year, j, err = parseInt(source, j, 4, 0, 9999, b); err != nil {
|
||||
return
|
||||
}
|
||||
year *= sign
|
||||
case 'g':
|
||||
hasISOYear = true
|
||||
fallthrough
|
||||
case 'y':
|
||||
if year, j, err = parseNumber(source, j, 2, 0, 99, 'y'); err != nil {
|
||||
if year, j, err = parseInt(source, j, 2, 0, 99, b); err != nil {
|
||||
return
|
||||
}
|
||||
if year < 69 {
|
||||
@@ -53,22 +59,16 @@ func parse(source, format string, loc, base *time.Location) (t time.Time, err er
|
||||
year += 1900
|
||||
}
|
||||
case 'C':
|
||||
if century, j, err = parseNumber(source, j, 2, 0, 99, 'C'); err != nil {
|
||||
sign, j = parseSign(source, j, l)
|
||||
if sign < 0 {
|
||||
err = errors.New(`negative century is not supported for "%C"`)
|
||||
return
|
||||
}
|
||||
case 'g':
|
||||
if year, j, err = parseNumber(source, j, 2, 0, 99, b); err != nil {
|
||||
if century, j, err = parseInt(source, j, 2, 0, 99, 'C'); err != nil {
|
||||
return
|
||||
}
|
||||
year += 2000
|
||||
hasISOYear = true
|
||||
case 'G':
|
||||
if year, j, err = parseNumber(source, j, 4, 0, 9999, b); err != nil {
|
||||
return
|
||||
}
|
||||
hasISOYear = true
|
||||
case 'm':
|
||||
if month, j, err = parseNumber(source, j, 2, 1, 12, 'm'); err != nil {
|
||||
if month, j, err = parseInt(source, j, 2, 1, 12, 'm'); err != nil {
|
||||
return
|
||||
}
|
||||
case 'B':
|
||||
@@ -88,29 +88,29 @@ func parse(source, format string, loc, base *time.Location) (t time.Time, err er
|
||||
return
|
||||
}
|
||||
case 'w':
|
||||
if weekday, j, err = parseNumber(source, j, 1, 0, 6, 'w'); err != nil {
|
||||
if weekday, j, err = parseInt(source, j, 1, 0, 6, 'w'); err != nil {
|
||||
return
|
||||
}
|
||||
weekday++
|
||||
case 'u':
|
||||
if weekday, j, err = parseNumber(source, j, 1, 1, 7, 'u'); err != nil {
|
||||
if weekday, j, err = parseInt(source, j, 1, 1, 7, 'u'); err != nil {
|
||||
return
|
||||
}
|
||||
weekday = weekday%7 + 1
|
||||
case 'V':
|
||||
if week, j, err = parseNumber(source, j, 2, 1, 53, b); err != nil {
|
||||
if week, j, err = parseInt(source, j, 2, 1, 53, b); err != nil {
|
||||
return
|
||||
}
|
||||
weekstart = time.Thursday
|
||||
weekday = or(weekday, 2)
|
||||
case 'U':
|
||||
if week, j, err = parseNumber(source, j, 2, 0, 53, b); err != nil {
|
||||
if week, j, err = parseInt(source, j, 2, 0, 53, b); err != nil {
|
||||
return
|
||||
}
|
||||
weekstart = time.Sunday
|
||||
weekday = or(weekday, 1)
|
||||
case 'W':
|
||||
if week, j, err = parseNumber(source, j, 2, 0, 53, b); err != nil {
|
||||
if week, j, err = parseInt(source, j, 2, 0, 53, b); err != nil {
|
||||
return
|
||||
}
|
||||
weekstart = time.Monday
|
||||
@@ -121,11 +121,11 @@ func parse(source, format string, loc, base *time.Location) (t time.Time, err er
|
||||
}
|
||||
fallthrough
|
||||
case 'd':
|
||||
if day, j, err = parseNumber(source, j, 2, 1, 31, b); err != nil {
|
||||
if day, j, err = parseInt(source, j, 2, 1, 31, b); err != nil {
|
||||
return
|
||||
}
|
||||
case 'j':
|
||||
if yday, j, err = parseNumber(source, j, 3, 1, 366, 'j'); err != nil {
|
||||
if yday, j, err = parseInt(source, j, 3, 1, 366, 'j'); err != nil {
|
||||
return
|
||||
}
|
||||
case 'k':
|
||||
@@ -134,7 +134,7 @@ func parse(source, format string, loc, base *time.Location) (t time.Time, err er
|
||||
}
|
||||
fallthrough
|
||||
case 'H':
|
||||
if hour, j, err = parseNumber(source, j, 2, 0, 23, b); err != nil {
|
||||
if hour, j, err = parseInt(source, j, 2, 0, 23, b); err != nil {
|
||||
return
|
||||
}
|
||||
case 'l':
|
||||
@@ -143,7 +143,7 @@ func parse(source, format string, loc, base *time.Location) (t time.Time, err er
|
||||
}
|
||||
fallthrough
|
||||
case 'I':
|
||||
if hour, j, err = parseNumber(source, j, 2, 1, 12, b); err != nil {
|
||||
if hour, j, err = parseInt(source, j, 2, 1, 12, b); err != nil {
|
||||
return
|
||||
}
|
||||
if hour == 12 {
|
||||
@@ -156,26 +156,27 @@ func parse(source, format string, loc, base *time.Location) (t time.Time, err er
|
||||
}
|
||||
pm = ampm == 2
|
||||
case 'M':
|
||||
if minute, j, err = parseNumber(source, j, 2, 0, 59, 'M'); err != nil {
|
||||
if minute, j, err = parseInt(source, j, 2, 0, 59, 'M'); err != nil {
|
||||
return
|
||||
}
|
||||
case 'S':
|
||||
if second, j, err = parseNumber(source, j, 2, 0, 60, 'S'); err != nil {
|
||||
if second, j, err = parseInt(source, j, 2, 0, 60, 'S'); err != nil {
|
||||
return
|
||||
}
|
||||
case 's':
|
||||
var unix int
|
||||
if unix, j, err = parseNumber(source, j, 10, 0, math.MaxInt, 's'); err != nil {
|
||||
sign, j = parseSign(source, j, l)
|
||||
var unix int64
|
||||
if unix, j, err = parseInt64(source, j, 19, 's'); err != nil {
|
||||
return
|
||||
}
|
||||
t = time.Unix(int64(unix), 0).In(time.UTC)
|
||||
t = time.Unix(int64(sign)*unix, 0).In(time.UTC)
|
||||
var mon time.Month
|
||||
year, mon, day = t.Date()
|
||||
hour, minute, second = t.Clock()
|
||||
month = int(mon)
|
||||
case 'f':
|
||||
microsecond, i := 0, j
|
||||
if microsecond, j, err = parseNumber(source, j, 6, 0, 999999, 'f'); err != nil {
|
||||
if microsecond, j, err = parseInt(source, j, 6, 0, 999999, 'f'); err != nil {
|
||||
return
|
||||
}
|
||||
for i = j - i; i < 6; i++ {
|
||||
@@ -207,19 +208,19 @@ func parse(source, format string, loc, base *time.Location) (t time.Time, err er
|
||||
err = parseZFormatError(colons)
|
||||
return
|
||||
}
|
||||
sign := 1
|
||||
sign = 1
|
||||
switch source[j] {
|
||||
case '-':
|
||||
sign = -1
|
||||
fallthrough
|
||||
case '+':
|
||||
hour, minute, second, i := 0, 0, 0, j
|
||||
if hour, j, _ = parseNumber(source, j+1, 2, 0, 23, 'z'); j != i+3 {
|
||||
hour, minute, second, i := 0, 0, 0, j+1
|
||||
if hour, j, _ = parseInt(source, i, 2, 0, 23, 'z'); j != i+2 {
|
||||
err = parseZFormatError(colons)
|
||||
return
|
||||
}
|
||||
if j >= l || source[j] != ':' {
|
||||
if colons > 0 {
|
||||
if colons > 0 && colons < 3 {
|
||||
err = expectedColonForZFormatError(colons)
|
||||
return
|
||||
}
|
||||
@@ -227,26 +228,26 @@ func parse(source, format string, loc, base *time.Location) (t time.Time, err er
|
||||
colons = 4
|
||||
}
|
||||
i = j
|
||||
if minute, j, _ = parseNumber(source, j, 2, 0, 59, 'z'); j != i+2 {
|
||||
if colons > 0 {
|
||||
if minute, j, _ = parseInt(source, i, 2, 0, 59, 'z'); j != i+2 {
|
||||
if colons > 0 && colons != 3 {
|
||||
err = parseZFormatError(colons & 3)
|
||||
return
|
||||
}
|
||||
j = i
|
||||
} else if colons > 1 {
|
||||
if j >= l || source[j] != ':' {
|
||||
if colons == 2 {
|
||||
if colons < 3 {
|
||||
err = expectedColonForZFormatError(colons)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
i = j
|
||||
if second, j, _ = parseNumber(source, j+1, 2, 0, 59, 'z'); j != i+3 {
|
||||
if colons == 2 {
|
||||
i = j + 1
|
||||
if second, j, _ = parseInt(source, i, 2, 0, 59, 'z'); j != i+2 {
|
||||
if colons < 3 {
|
||||
err = parseZFormatError(colons)
|
||||
return
|
||||
}
|
||||
j = i
|
||||
j = i - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -270,12 +271,12 @@ func parse(source, format string, loc, base *time.Location) (t time.Time, err er
|
||||
}
|
||||
j++
|
||||
} else {
|
||||
for colons = 1; colons <= 2; colons++ {
|
||||
for colons = 1; colons <= 3; colons++ {
|
||||
if i++; i == len(format) {
|
||||
break
|
||||
} else if b = format[i]; b == 'z' {
|
||||
goto L
|
||||
} else if b != ':' || colons == 2 {
|
||||
} else if b != ':' || colons == 3 {
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -302,12 +303,24 @@ func parse(source, format string, loc, base *time.Location) (t time.Time, err er
|
||||
return
|
||||
}
|
||||
j++
|
||||
case 'c':
|
||||
pending = "a b e H:M:S Y"
|
||||
case '+':
|
||||
pending = "a b e H:M:S Z Y"
|
||||
case 'v':
|
||||
pending = "e-b-Y"
|
||||
case 'r':
|
||||
pending = "I:M:S p"
|
||||
case 'F':
|
||||
pending = "Y-m-d"
|
||||
case 'D', 'x':
|
||||
pending = "m/d/y"
|
||||
case 'T', 'X':
|
||||
pending = "H:M:S"
|
||||
case 'R':
|
||||
pending = "H:M"
|
||||
default:
|
||||
if pending == "" {
|
||||
var ok bool
|
||||
if pending, ok = compositions[b]; ok {
|
||||
break
|
||||
}
|
||||
err = fmt.Errorf(`unexpected format "%%%c"`, b)
|
||||
return
|
||||
}
|
||||
@@ -386,27 +399,37 @@ func (err expectedFormatError) Error() string {
|
||||
type parseZFormatError int
|
||||
|
||||
func (err parseZFormatError) Error() string {
|
||||
return `cannot parse "%` + `::z"`[2-err:]
|
||||
return `cannot parse "%` + `:::z"`[3-err:]
|
||||
}
|
||||
|
||||
type expectedColonForZFormatError int
|
||||
|
||||
func (err expectedColonForZFormatError) Error() string {
|
||||
return `expected ':' for "%` + `::z"`[2-err:]
|
||||
return `expected ':' for "%` + `:::z"`[3-err:]
|
||||
}
|
||||
|
||||
type expectedZAfterColonError int
|
||||
|
||||
func (err expectedZAfterColonError) Error() string {
|
||||
return `expected 'z' after "%` + `::"`[2-err:]
|
||||
return `expected 'z' after "%` + `:::"`[3-err:]
|
||||
}
|
||||
|
||||
func parseNumber(source string, index, size, minimum, maximum int, format byte) (int, int, error) {
|
||||
func parseSign(source string, index, l int) (int, int) {
|
||||
if index < l && source[index] == '-' {
|
||||
return -1, index + 1
|
||||
}
|
||||
return 1, index
|
||||
}
|
||||
|
||||
// parseInt parses an integer from source. This is intentionally not a
|
||||
// wrapper of parseInt64 to avoid the overhead of int64 arithmetic and
|
||||
// function call indirection in the hot path (~20% slower in benchmarks).
|
||||
func parseInt(source string, index, size, minimum, maximum int, format byte) (int, int, error) {
|
||||
var value int
|
||||
i := index
|
||||
for size = min(i+size, len(source)); i < size; i++ {
|
||||
if b := source[i]; '0' <= b && b <= '9' {
|
||||
value = value*10 + int(b&0x0F)
|
||||
if b := source[i] - '0'; b < 10 {
|
||||
value = value*10 + int(b)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
@@ -417,6 +440,22 @@ func parseNumber(source string, index, size, minimum, maximum int, format byte)
|
||||
return value, i, nil
|
||||
}
|
||||
|
||||
func parseInt64(source string, index, size int, format byte) (int64, int, error) {
|
||||
var value int64
|
||||
i := index
|
||||
for size = min(i+size, len(source)); i < size; i++ {
|
||||
if b := source[i] - '0'; b < 10 {
|
||||
value = value*10 + int64(b)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if i == index {
|
||||
return 0, 0, parseFormatError(format)
|
||||
}
|
||||
return value, i, nil
|
||||
}
|
||||
|
||||
func parseAny(source string, index int, candidates []string, format byte) (int, int, error) {
|
||||
L:
|
||||
for i, xs := range candidates {
|
||||
|
||||
Vendored
+2
-2
@@ -461,10 +461,10 @@ github.com/huandu/xstrings
|
||||
# github.com/inconshreveable/mousetrap v1.1.0
|
||||
## explicit; go 1.18
|
||||
github.com/inconshreveable/mousetrap
|
||||
# github.com/itchyny/gojq v0.12.18
|
||||
# github.com/itchyny/gojq v0.12.19
|
||||
## explicit; go 1.24.0
|
||||
github.com/itchyny/gojq
|
||||
# github.com/itchyny/timefmt-go v0.1.7
|
||||
# github.com/itchyny/timefmt-go v0.1.8
|
||||
## explicit; go 1.24
|
||||
github.com/itchyny/timefmt-go
|
||||
# github.com/json-iterator/go v1.1.12
|
||||
|
||||
Reference in New Issue
Block a user