diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 65b66d8..aef7ae3 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -13,12 +13,12 @@ jobs:
     strategy:
       matrix:
         os: [ubuntu-latest, macos-latest, windows-latest]
-        go: [1.17.x, 1.16.x]
+        go: [1.18.x, 1.17.x, 1.16.x]
     steps:
     - name: Checkout code
-      uses: actions/checkout@v2
+      uses: actions/checkout@v3
     - name: Setup Go
-      uses: actions/setup-go@v2
+      uses: actions/setup-go@v3
       with:
         go-version: ${{ matrix.go }}
     - name: Test
@@ -28,6 +28,7 @@ jobs:
       if: matrix.os != 'macos-latest'
     - name: Lint
       run: make lint
+      if: matrix.go >= '1.18.x'
     - name: Check tools
       run: make check-tools
     - name: Check go generate
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index dbdb1dc..803a288 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -13,10 +13,10 @@ jobs:
     steps:
 
     - name: Checkout code
-      uses: actions/checkout@v2
+      uses: actions/checkout@v3
 
     - name: Setup Go
-      uses: actions/setup-go@v2
+      uses: actions/setup-go@v3
       with:
         go-version: 1.x
 
diff --git a/Dockerfile b/Dockerfile
index 7beaf4e..dfe416b 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM golang:1.17 AS builder
+FROM golang:1.18 AS builder
 
 WORKDIR /app
 COPY . .
diff --git a/Makefile b/Makefile
index b5de912..46d0be7 100644
--- a/Makefile
+++ b/Makefile
@@ -19,7 +19,7 @@ build-dev: parser.go builtin.go
 
 .PHONY: build-debug
 build-debug: parser.go builtin.go
-	go build -tags debug -ldflags=$(BUILD_LDFLAGS) -o $(BIN) ./cmd/$(BIN)
+	go build -tags gojq_debug -ldflags=$(BUILD_LDFLAGS) -o $(BIN) ./cmd/$(BIN)
 
 builtin.go: builtin.jq parser.go.y parser.go query.go operator.go _tools/*
 	GOOS= GOARCH= go generate
@@ -41,7 +41,7 @@ install-dev: parser.go builtin.go
 
 .PHONY: install-debug
 install-debug: parser.go builtin.go
-	go install -tags debug -ldflags=$(BUILD_LDFLAGS) ./...
+	go install -tags gojq_debug -ldflags=$(BUILD_LDFLAGS) ./...
 
 .PHONY: show-version
 show-version: $(GOBIN)/gobump
@@ -52,7 +52,7 @@ $(GOBIN)/gobump:
 
 .PHONY: cross
 cross: $(GOBIN)/goxz CREDITS
-	goxz -n $(BIN) -pv=v$(VERSION) -include _$(BIN) -arch=amd64,arm64 \
+	goxz -n $(BIN) -pv=v$(VERSION) -include _$(BIN) \
 		-build-ldflags=$(BUILD_LDFLAGS) ./cmd/$(BIN)
 
 $(GOBIN)/goxz:
@@ -72,7 +72,7 @@ test: build
 .PHONY: lint
 lint: $(GOBIN)/staticcheck
 	go vet ./...
-	staticcheck -checks all,-ST1000 -tags debug ./...
+	staticcheck -checks all,-ST1000 -tags gojq_debug ./...
 
 $(GOBIN)/staticcheck:
 	go install honnef.co/go/tools/cmd/staticcheck@latest
diff --git a/README.md b/README.md
index baba061..8a93c54 100644
--- a/README.md
+++ b/README.md
@@ -78,7 +78,7 @@ docker run -i --rm ghcr.io/itchyny/gojq
 - gojq does not keep the order of object keys. I understand this might cause problems for some scripts but basically, we should not rely on the order of object keys. Due to this limitation, gojq does not have `keys_unsorted` function and `--sort-keys` (`-S`) option. I would implement when ordered map is implemented in the standard library of Go but I'm less motivated. Also, gojq assumes only valid JSON input while jq deals with some JSON extensions; `NaN`, `Infinity` and `[000]`.
 - gojq supports arbitrary-precision integer calculation while jq does not. This is important to keep the precision of numeric IDs or nanosecond values. You can also use gojq to solve some mathematical problems which require big integers. Note that mathematical functions convert integers to floating-point numbers; only addition, subtraction, multiplication, modulo operation, and division (when divisible) keep integer precisions. When you want to calculate floor division of big integers, use `def intdiv($x; $y): ($x - $x % $y) / $y;`, instead of `$x / $y`.
 - gojq fixes various bugs of jq. gojq correctly deletes elements of arrays by `|= empty` ([jq#2051](https://github.com/stedolan/jq/issues/2051)). gojq fixes `try`/`catch` handling ([jq#1859](https://github.com/stedolan/jq/issues/1859), [jq#1885](https://github.com/stedolan/jq/issues/1885), [jq#2140](https://github.com/stedolan/jq/issues/2140)). gojq fixes `nth/2` to output nothing when the count is equal to or larger than the stream size ([jq#1867](https://github.com/stedolan/jq/issues/1867)). gojq consistently counts by characters (not by bytes) in `index`, `rindex`, and `indices` functions; `"12345" | .[index("3"):]` results in `"345"` ([jq#1430](https://github.com/stedolan/jq/issues/1430), [jq#1624](https://github.com/stedolan/jq/issues/1624)), and supports string indexing; `"abcde"[2]` ([jq#1520](https://github.com/stedolan/jq/issues/1520)). gojq accepts indexing query `.e0` ([jq#1526](https://github.com/stedolan/jq/issues/1526), [jq#1651](https://github.com/stedolan/jq/issues/1651)), and allows `gsub` to handle patterns including `"^"` ([jq#2148](https://github.com/stedolan/jq/issues/2148)). gojq improves variable lexer to allow using keywords for variable names, especially in binding patterns, also disallows spaces after `$` ([jq#526](https://github.com/stedolan/jq/issues/526)). gojq fixes handling files with no newline characters at the end ([jq#2374](https://github.com/stedolan/jq/issues/2374)).
-- gojq implements `@uri` to escape all the reserved characters defined in RFC 3986, Sec. 2.2 ([jq#1506](https://github.com/stedolan/jq/issues/1506)), and fixes `@base64d` to allow binary string as the decoded string ([jq#1931](https://github.com/stedolan/jq/issues/1931)). gojq improves time formatting and parsing, deals with `%f` in `strftime` and `strptime` ([jq#1409](https://github.com/stedolan/jq/issues/1409)), parses timezone offsets with `fromdate` and `fromdateiso8601` ([jq#1053](https://github.com/stedolan/jq/issues/1053)), supports timezone name/offset with `%Z`/`%z` in `strptime` ([jq#929](https://github.com/stedolan/jq/issues/929), [jq#2195](https://github.com/stedolan/jq/issues/2195)), and looks up correct timezone during daylight saving time on formatting with `%Z` ([jq#1912](https://github.com/stedolan/jq/issues/1912)).
+- gojq implements `@uri` to escape all the reserved characters defined in RFC 3986, Sec. 2.2 ([jq#1506](https://github.com/stedolan/jq/issues/1506)), and fixes `@base64d` to allow binary string as the decoded string ([jq#1931](https://github.com/stedolan/jq/issues/1931)). gojq improves time formatting and parsing; deals with `%f` in `strftime` and `strptime` ([jq#1409](https://github.com/stedolan/jq/issues/1409)), parses timezone offsets with `fromdate` and `fromdateiso8601` ([jq#1053](https://github.com/stedolan/jq/issues/1053)), supports timezone name/offset with `%Z`/`%z` in `strptime` ([jq#929](https://github.com/stedolan/jq/issues/929), [jq#2195](https://github.com/stedolan/jq/issues/2195)), and looks up correct timezone during daylight saving time on formatting with `%Z` ([jq#1912](https://github.com/stedolan/jq/issues/1912)). gojq supports nanoseconds in date and time functions.
 - gojq does not support some functions intentionally; `get_jq_origin`, `get_prog_origin`, `get_search_list` (unstable, not listed in jq document), `input_line_number`, `$__loc__` (performance issue), `recurse_down` (deprecated in jq). gojq does not support some flags; `--ascii-output, -a` (performance issue), `--seq` (not used commonly), `--sort-keys, -S` (sorts by default because `map[string]interface{}` does not keep the order), `--unbuffered` (unbuffered by default). gojq normalizes floating-point numbers to fit to double-precision floating-point numbers. gojq does not support some regular expression flags (regular expression engine differences). gojq does not support BOM (`encoding/json` does not support this). gojq disallows using keywords for function names (declaration of `def true: .;` is a confusing query).
 - gojq supports reading from YAML input (`--yaml-input`) while jq does not. gojq also supports YAML output (`--yaml-output`).
 
diff --git a/_tools/gen_builtin.go b/_tools/gen_builtin.go
index be34a15..6af0fe9 100644
--- a/_tools/gen_builtin.go
+++ b/_tools/gen_builtin.go
@@ -37,20 +37,16 @@ func run(input, output string) error {
 	if err != nil {
 		return err
 	}
-	qs := make(map[string][]*gojq.FuncDef)
 	q, err := gojq.Parse(string(cnt))
 	if err != nil {
 		return err
 	}
+	fds := make(map[string][]*gojq.FuncDef)
 	for _, fd := range q.FuncDefs {
-		name := fd.Name
-		if name[0] == '_' {
-			name = name[1:]
-		}
 		fd.Minify()
-		qs[name] = append(qs[fd.Name], fd)
+		fds[fd.Name] = append(fds[fd.Name], fd)
 	}
-	t, err := astgen.Build(qs)
+	t, err := astgen.Build(fds)
 	if err != nil {
 		return err
 	}
diff --git a/_tools/print_builtin.go b/_tools/print_builtin.go
index 00ec180..8169a30 100644
--- a/_tools/print_builtin.go
+++ b/_tools/print_builtin.go
@@ -15,18 +15,14 @@ func main() {
 	if err != nil {
 		panic(err)
 	}
-	fds := make(map[string][]*gojq.FuncDef)
 	q, err := gojq.Parse(string(cnt))
 	if err != nil {
 		panic(err)
 	}
+	fds := make(map[string][]*gojq.FuncDef)
 	for _, fd := range q.FuncDefs {
-		name := fd.Name
-		if name[0] == '_' {
-			name = name[1:]
-		}
 		fd.Minify()
-		fds[name] = append(fds[fd.Name], fd)
+		fds[fd.Name] = append(fds[fd.Name], fd)
 	}
 	count := len(fds)
 	names, i := make([]string, count), 0
@@ -36,13 +32,13 @@ func main() {
 	}
 	sort.Strings(names)
 	for _, n := range names {
-		var s strings.Builder
+		var sb strings.Builder
 		for _, fd := range fds[n] {
-			fmt.Fprintf(&s, "%s ", fd)
+			fmt.Fprintf(&sb, "%s ", fd)
 		}
-		q, err := gojq.Parse(s.String())
+		q, err := gojq.Parse(sb.String())
 		if err != nil {
-			panic(fmt.Sprintf("%s: %s", err, s.String()))
+			panic(fmt.Sprintf("%s: %s", err, sb.String()))
 		}
 		for _, fd := range q.FuncDefs {
 			fd.Minify()
@@ -51,7 +47,7 @@ func main() {
 			fmt.Printf("failed: %s: %s %s\n", n, q.FuncDefs, fds[n])
 			continue
 		}
-		fmt.Printf("ok: %s: %s\n", n, s.String())
+		fmt.Printf("ok: %s: %s\n", n, sb.String())
 		count--
 	}
 	if count > 0 {
diff --git a/builtin.go b/builtin.go
index 65f9e23..a59795d 100644
--- a/builtin.go
+++ b/builtin.go
@@ -7,74 +7,59 @@ func init() {
 		"IN": []*FuncDef{&FuncDef{Name: "IN", Args: []string{"s"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "any", Args: []*Query{&Query{Left: &Query{Func: "s"}, Op: OpEq, Right: &Query{Func: "."}}, &Query{Func: "."}}}}}}, &FuncDef{Name: "IN", Args: []string{"src", "s"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "any", Args: []*Query{&Query{Left: &Query{Func: "src"}, Op: OpEq, Right: &Query{Func: "s"}}, &Query{Func: "."}}}}}}},
 		"INDEX": []*FuncDef{&FuncDef{Name: "INDEX", Args: []string{"stream", "idx_expr"}, Body: &Query{Term: &Term{Type: TermTypeReduce, Reduce: &Reduce{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "stream"}}, Pattern: &Pattern{Name: "$row"}, Start: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{}}}, Update: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Left: &Query{Func: "$row"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "idx_expr"}, Op: OpPipe, Right: &Query{Func: "tostring"}}}}}}, Op: OpAssign, Right: &Query{Func: "$row"}}}}}}, &FuncDef{Name: "INDEX", Args: []string{"idx_expr"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "INDEX", Args: []*Query{&Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}, &Query{Func: "idx_expr"}}}}}}},
 		"JOIN": []*FuncDef{&FuncDef{Name: "JOIN", Args: []string{"$idx", "idx_expr"}, Body: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Func: "."}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$idx"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Func: "idx_expr"}}}}}}}}}}}}}}}, &FuncDef{Name: "JOIN", Args: []string{"$idx", "stream", "idx_expr"}, Body: &Query{Left: &Query{Func: "stream"}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Func: "."}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$idx"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Func: "idx_expr"}}}}}}}}}}}}, &FuncDef{Name: "JOIN", Args: []string{"$idx", "stream", "idx_expr", "join_expr"}, Body: &Query{Left: &Query{Func: "stream"}, Op: OpPipe, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Func: "."}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$idx"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Func: "idx_expr"}}}}}}}}}}, Op: OpPipe, Right: &Query{Func: "join_expr"}}}}},
-		"all": []*FuncDef{&FuncDef{Name: "all", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "all", Args: []*Query{&Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}, &Query{Func: "."}}}}}}, &FuncDef{Name: "all", Args: []string{"y"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "all", Args: []*Query{&Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}, &Query{Func: "y"}}}}}}, &FuncDef{Name: "all", Args: []string{"g", "y"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "isempty", Args: []*Query{&Query{Left: &Query{Func: "g"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "y"}, Op: OpAnd, Right: &Query{Func: "empty"}}}}}}}}},
-		"any": []*FuncDef{&FuncDef{Name: "any", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "any", Args: []*Query{&Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}, &Query{Func: "."}}}}}}, &FuncDef{Name: "any", Args: []string{"y"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "any", Args: []*Query{&Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}, &Query{Func: "y"}}}}}}, &FuncDef{Name: "any", Args: []string{"g", "y"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "isempty", Args: []*Query{&Query{Left: &Query{Func: "g"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "y"}, Op: OpOr, Right: &Query{Func: "empty"}}}}}}}, Op: OpPipe, Right: &Query{Func: "not"}}}},
+		"_assign": []*FuncDef{&FuncDef{Name: "_assign", Args: []string{"ps", "$v"}, Body: &Query{Term: &Term{Type: TermTypeReduce, Reduce: &Reduce{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "path", Args: []*Query{&Query{Func: "ps"}}}}, Pattern: &Pattern{Name: "$p"}, Start: &Query{Func: "."}, Update: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "setpath", Args: []*Query{&Query{Func: "$p"}, &Query{Func: "$v"}}}}}}}}}},
+		"_modify": []*FuncDef{&FuncDef{Name: "_modify", Args: []string{"ps", "f"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeReduce, Reduce: &Reduce{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "path", Args: []*Query{&Query{Func: "ps"}}}}, Pattern: &Pattern{Name: "$p"}, Start: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Func: "."}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{}}}}}}}, Update: &Query{Term: &Term{Type: TermTypeLabel, Label: &Label{Ident: "$out", Body: &Query{Left: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}, Op: OpAdd, Right: &Query{Func: "$p"}}, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$q"}}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "setpath", Args: []*Query{&Query{Func: "$q"}, &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "getpath", Args: []*Query{&Query{Func: "$q"}}}}}, Op: OpPipe, Right: &Query{Func: "f"}}}}}}, Op: OpPipe, Right: &Query{Left: &Query{Func: "."}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeBreak, Break: "$out"}}}}}}}}}}}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "setpath", Args: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}, &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Func: "$p"}}}}}}}}}}}}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$x"}}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$x"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "delpaths", Args: []*Query{&Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$x"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}}}}}}}}}}}}}}}},
+		"all": []*FuncDef{&FuncDef{Name: "all", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "all", Args: []*Query{&Query{Func: "."}}}}}}, &FuncDef{Name: "all", Args: []string{"y"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "all", Args: []*Query{&Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}, &Query{Func: "y"}}}}}}, &FuncDef{Name: "all", Args: []string{"g", "y"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "isempty", Args: []*Query{&Query{Left: &Query{Func: "g"}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Func: "y"}, Op: OpPipe, Right: &Query{Func: "not"}}}}}}}}}}}}},
+		"any": []*FuncDef{&FuncDef{Name: "any", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "any", Args: []*Query{&Query{Func: "."}}}}}}, &FuncDef{Name: "any", Args: []string{"y"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "any", Args: []*Query{&Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}, &Query{Func: "y"}}}}}}, &FuncDef{Name: "any", Args: []string{"g", "y"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "isempty", Args: []*Query{&Query{Left: &Query{Func: "g"}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Func: "y"}}}}}}}}}}, Op: OpPipe, Right: &Query{Func: "not"}}}},
 		"arrays": []*FuncDef{&FuncDef{Name: "arrays", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "array"}}}}}}}}}},
 		"ascii_downcase": []*FuncDef{&FuncDef{Name: "ascii_downcase", Body: &Query{Left: &Query{Func: "explode"}, Op: OpPipe, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "map", Args: []*Query{&Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Left: &Query{Term: &Term{Type: TermTypeNumber, Number: "65"}}, Op: OpLe, Right: &Query{Func: "."}}, Op: OpAnd, Right: &Query{Left: &Query{Func: "."}, Op: OpLe, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "90"}}}}, Then: &Query{Left: &Query{Func: "."}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "32"}}}}}}}}}}, Op: OpPipe, Right: &Query{Func: "implode"}}}}},
 		"ascii_upcase": []*FuncDef{&FuncDef{Name: "ascii_upcase", Body: &Query{Left: &Query{Func: "explode"}, Op: OpPipe, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "map", Args: []*Query{&Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Left: &Query{Term: &Term{Type: TermTypeNumber, Number: "97"}}, Op: OpLe, Right: &Query{Func: "."}}, Op: OpAnd, Right: &Query{Left: &Query{Func: "."}, Op: OpLe, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "122"}}}}, Then: &Query{Left: &Query{Func: "."}, Op: OpSub, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "32"}}}}}}}}}}, Op: OpPipe, Right: &Query{Func: "implode"}}}}},
-		"assign": []*FuncDef{&FuncDef{Name: "_assign", Args: []string{"ps", "$v"}, Body: &Query{Term: &Term{Type: TermTypeReduce, Reduce: &Reduce{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "path", Args: []*Query{&Query{Func: "ps"}}}}, Pattern: &Pattern{Name: "$p"}, Start: &Query{Func: "."}, Update: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "setpath", Args: []*Query{&Query{Func: "$p"}, &Query{Func: "$v"}}}}}}}}}},
 		"booleans": []*FuncDef{&FuncDef{Name: "booleans", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "boolean"}}}}}}}}}},
-		"capture": []*FuncDef{&FuncDef{Name: "capture", Args: []string{"$re"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "capture", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "null"}}}}}}, &FuncDef{Name: "capture", Args: []string{"$re", "$flags"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "match", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "$flags"}}}}}, Op: OpPipe, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "captures"}, SuffixList: []*Suffix{&Suffix{Iter: true}}}}, Op: OpPipe, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "name"}}}, Op: OpNe, Right: &Query{Func: "null"}}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{&ObjectKeyVal{KeyQuery: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "name"}}}, Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "string"}}}}}}}}}}}}}}}, Op: OpPipe, Right: &Query{Left: &Query{Func: "add"}, Op: OpAlt, Right: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{}}}}}}}},
-		"combinations": []*FuncDef{&FuncDef{Name: "combinations", Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "length"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, Then: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{}}}, Else: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, SuffixList: []*Suffix{&Suffix{Iter: true}, &Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$x"}}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}, IsSlice: true}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "combinations"}, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$y"}}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Func: "$x"}}}}, Op: OpAdd, Right: &Query{Func: "$y"}}}}}}}}}}}}}}}}}, &FuncDef{Name: "combinations", Args: []string{"n"}, Body: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$dot"}}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "range", Args: []*Query{&Query{Func: "n"}}}}}, Op: OpPipe, Right: &Query{Func: "$dot"}}}}}, Op: OpPipe, Right: &Query{Func: "combinations"}}}}}}}}},
+		"capture": []*FuncDef{&FuncDef{Name: "capture", Args: []string{"$re"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "capture", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "null"}}}}}}, &FuncDef{Name: "capture", Args: []string{"$re", "$flags"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "match", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "$flags"}}}}}, Op: OpPipe, Right: &Query{Func: "_capture"}}}},
+		"combinations": []*FuncDef{&FuncDef{Name: "combinations", Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "length"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, Then: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{}}}, Else: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, SuffixList: []*Suffix{&Suffix{Iter: true}, &Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$x"}}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Func: "$x"}}}}, Op: OpAdd, 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}}}, Op: OpPipe, Right: &Query{Func: "combinations"}}}}}}}}}}}}}}, &FuncDef{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{&Query{Func: "n"}, &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "repeat", Args: []*Query{&Query{Func: "."}}}}}}}}}}}}, Op: OpPipe, Right: &Query{Func: "combinations"}}}},
 		"del": []*FuncDef{&FuncDef{Name: "del", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "delpaths", Args: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "path", Args: []*Query{&Query{Func: "f"}}}}}}}}}}}}}},
-		"endswith": []*FuncDef{&FuncDef{Name: "endswith", Args: []string{"$x"}, Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "string"}}}}, Then: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "$x"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "string"}}}}}, Then: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeUnary, Unary: &Unary{Op: OpSub, Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Func: "$x"}, Op: OpPipe, Right: &Query{Func: "length"}}}}}}, IsSlice: true}}}, Op: OpEq, Right: &Query{Func: "$x"}}, Else: &Query{Left: &Query{Func: "$x"}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_type_error", Args: []*Query{&Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "endswith"}}}}}}}}}}}, Else: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_type_error", Args: []*Query{&Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "endswith"}}}}}}}}}}}},
 		"finites": []*FuncDef{&FuncDef{Name: "finites", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Func: "isfinite"}}}}}}},
 		"first": []*FuncDef{&FuncDef{Name: "first", Body: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}}, &FuncDef{Name: "first", Args: []string{"g"}, Body: &Query{Term: &Term{Type: TermTypeLabel, Label: &Label{Ident: "$out", Body: &Query{Left: &Query{Func: "g"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "."}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeBreak, Break: "$out"}}}}}}}}},
-		"flatten": []*FuncDef{&FuncDef{Name: "_flatten", Args: []string{"$x"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "map", Args: []*Query{&Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "array"}}}}, Op: OpAnd, Right: &Query{Left: &Query{Func: "$x"}, Op: OpNe, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}, Then: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_flatten", Args: []*Query{&Query{Left: &Query{Func: "$x"}, Op: OpSub, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}}}, Else: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Func: "."}}}}}}}}}}}, Op: OpPipe, Right: &Query{Func: "add"}}}, &FuncDef{Name: "flatten", Args: []string{"$x"}, Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "$x"}, Op: OpLt, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, Then: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "error", Args: []*Query{&Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "flatten depth must not be negative"}}}}}}}, Else: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_flatten", Args: []*Query{&Query{Func: "$x"}}}}}, Op: OpAlt, Right: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{}}}}}}}}, &FuncDef{Name: "flatten", Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_flatten", Args: []*Query{&Query{Term: &Term{Type: TermTypeUnary, Unary: &Unary{Op: OpSub, Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}}}}, Op: OpAlt, Right: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{}}}}}},
-		"from_entries": []*FuncDef{&FuncDef{Name: "from_entries", Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "map", Args: []*Query{&Query{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{&ObjectKeyVal{KeyQuery: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "key"}}}, Op: OpAlt, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "Key"}}}, Op: OpAlt, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "name"}}}, Op: OpAlt, Right: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "Name"}}}}}}, Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "has", Args: []*Query{&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"}}}}}}}}}}}}}}}}}}}, Op: OpPipe, Right: &Query{Left: &Query{Func: "add"}, Op: OpAlt, Right: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{}}}}}}},
 		"fromdate": []*FuncDef{&FuncDef{Name: "fromdate", Body: &Query{Func: "fromdateiso8601"}}},
 		"fromdateiso8601": []*FuncDef{&FuncDef{Name: "fromdateiso8601", Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "strptime", Args: []*Query{&Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "%Y-%m-%dT%H:%M:%S%z"}}}}}}}, Op: OpPipe, Right: &Query{Func: "mktime"}}}},
 		"fromstream": []*FuncDef{&FuncDef{Name: "fromstream", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{&ObjectKeyVal{Key: "x", Val: &ObjectVal{Queries: []*Query{&Query{Func: "null"}}}}, &ObjectKeyVal{Key: "e", Val: &ObjectVal{Queries: []*Query{&Query{Func: "false"}}}}}}, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$init"}}, Body: &Query{Term: &Term{Type: TermTypeForeach, Foreach: &Foreach{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "f"}}, Pattern: &Pattern{Name: "$i"}, Start: &Query{Func: "$init"}, Update: &Query{Left: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "e"}}}, Then: &Query{Func: "$init"}, Else: &Query{Func: "."}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "$i"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "length"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "2"}}}}, Then: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "setpath", Args: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "e"}}}}}}, &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$i"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}}}, Op: OpPipe, Right: &Query{Left: &Query{Func: "length"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "setpath", Args: []*Query{&Query{Left: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "x"}}}}}}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$i"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}}}}, &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$i"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}}}}}}}}, Else: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "setpath", Args: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "e"}}}}}}, &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$i"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}}}, Op: OpPipe, Right: &Query{Left: &Query{Func: "length"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}}}}}}}}, 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: "x"}}}, Else: &Query{Func: "empty"}}}}}}}}}}}}}},
 		"group_by": []*FuncDef{&FuncDef{Name: "group_by", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_group_by", Args: []*Query{&Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "map", Args: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Func: "f"}}}}}}}}}}}}}},
 		"gsub": []*FuncDef{&FuncDef{Name: "gsub", Args: []string{"$re", "str"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "sub", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "str"}, &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "g"}}}}}}}}, &FuncDef{Name: "gsub", Args: []string{"$re", "str", "$flags"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "sub", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "str"}, &Query{Left: &Query{Func: "$flags"}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "g"}}}}}}}}}},
 		"in": []*FuncDef{&FuncDef{Name: "in", Args: []string{"xs"}, Body: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$x"}}, Body: &Query{Left: &Query{Func: "xs"}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "has", Args: []*Query{&Query{Func: "$x"}}}}}}}}}}}}},
-		"index": []*FuncDef{&FuncDef{Name: "index", Args: []string{"$x"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_lindex", Args: []*Query{&Query{Func: "$x"}}}}}}},
-		"indices": []*FuncDef{&FuncDef{Name: "indices", Args: []string{"$x"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_indices", Args: []*Query{&Query{Func: "$x"}}}}}}},
 		"inputs": []*FuncDef{&FuncDef{Name: "inputs", Body: &Query{Term: &Term{Type: TermTypeTry, Try: &Try{Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "repeat", Args: []*Query{&Query{Func: "input"}}}}}, Catch: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "."}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "break"}}}}, Then: &Query{Func: "empty"}, Else: &Query{Func: "error"}}}}}}}}},
 		"inside": []*FuncDef{&FuncDef{Name: "inside", Args: []string{"xs"}, Body: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$x"}}, Body: &Query{Left: &Query{Func: "xs"}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "contains", Args: []*Query{&Query{Func: "$x"}}}}}}}}}}}}},
 		"isempty": []*FuncDef{&FuncDef{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{Func: "g"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "false"}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeBreak, Break: "$out"}}}}}}, Op: OpComma, Right: &Query{Func: "true"}}}}}}},
 		"iterables": []*FuncDef{&FuncDef{Name: "iterables", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Func: "type"}, Op: OpPipe, Right: &Query{Left: &Query{Left: &Query{Func: "."}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "array"}}}}, Op: OpOr, Right: &Query{Left: &Query{Func: "."}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "object"}}}}}}}}}}}},
-		"join": []*FuncDef{&FuncDef{Name: "join", Args: []string{"$x"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "type"}, Op: OpNe, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "array"}}}}, Then: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}}}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_join", Args: []*Query{&Query{Func: "$x"}}}}}}}},
 		"last": []*FuncDef{&FuncDef{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"}}}}}}}}, &FuncDef{Name: "last", Args: []string{"g"}, Body: &Query{Term: &Term{Type: TermTypeReduce, Reduce: &Reduce{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "g"}}, Pattern: &Pattern{Name: "$item"}, Start: &Query{Func: "null"}, Update: &Query{Func: "$item"}}}}}},
 		"leaf_paths": []*FuncDef{&FuncDef{Name: "leaf_paths", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "paths", Args: []*Query{&Query{Func: "scalars"}}}}}}},
 		"limit": []*FuncDef{&FuncDef{Name: "limit", Args: []string{"$n", "g"}, Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "$n"}, Op: OpGt, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, Then: &Query{Term: &Term{Type: TermTypeLabel, Label: &Label{Ident: "$out", Body: &Query{Term: &Term{Type: TermTypeForeach, Foreach: &Foreach{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "g"}}, Pattern: &Pattern{Name: "$item"}, Start: &Query{Func: "$n"}, Update: &Query{Left: &Query{Func: "."}, Op: OpSub, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}, Extract: &Query{Left: &Query{Func: "$item"}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "."}, Op: OpLe, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, Then: &Query{Term: &Term{Type: TermTypeBreak, Break: "$out"}}, Else: &Query{Func: "empty"}}}}}}}}}}}, Elif: []*IfElif{&IfElif{Cond: &Query{Left: &Query{Func: "$n"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, Then: &Query{Func: "empty"}}}, Else: &Query{Func: "g"}}}}}},
-		"ltrimstr": []*FuncDef{&FuncDef{Name: "ltrimstr", Args: []string{"$x"}, Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Left: &Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "string"}}}}, Op: OpAnd, Right: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Func: "$x"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "string"}}}}}}}}, Op: OpAnd, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "startswith", Args: []*Query{&Query{Func: "$x"}}}}}}, Then: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Left: &Query{Func: "$x"}, Op: OpPipe, Right: &Query{Func: "length"}}, IsSlice: true}}}}}}}},
 		"map": []*FuncDef{&FuncDef{Name: "map", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}, Op: OpPipe, Right: &Query{Func: "f"}}}}}}},
 		"map_values": []*FuncDef{&FuncDef{Name: "map_values", Args: []string{"f"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}, Op: OpModify, Right: &Query{Func: "f"}}}},
 		"match": []*FuncDef{&FuncDef{Name: "match", Args: []string{"$re"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "match", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "null"}}}}}}, &FuncDef{Name: "match", Args: []string{"$re", "$flags"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_match", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "$flags"}, &Query{Func: "false"}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}}}},
-		"max": []*FuncDef{&FuncDef{Name: "max", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "max_by", Args: []*Query{&Query{Func: "."}}}}}}},
 		"max_by": []*FuncDef{&FuncDef{Name: "max_by", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_max_by", Args: []*Query{&Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "map", Args: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Func: "f"}}}}}}}}}}}}}},
-		"min": []*FuncDef{&FuncDef{Name: "min", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "min_by", Args: []*Query{&Query{Func: "."}}}}}}},
 		"min_by": []*FuncDef{&FuncDef{Name: "min_by", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_min_by", Args: []*Query{&Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "map", Args: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Func: "f"}}}}}}}}}}}}}},
-		"modify": []*FuncDef{&FuncDef{Name: "_modify", Args: []string{"ps", "f"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeReduce, Reduce: &Reduce{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "path", Args: []*Query{&Query{Func: "ps"}}}}, Pattern: &Pattern{Name: "$p"}, Start: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Func: "."}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{}}}}}}}, Update: &Query{Term: &Term{Type: TermTypeLabel, Label: &Label{Ident: "$out", Body: &Query{Left: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}, Op: OpAdd, Right: &Query{Func: "$p"}}, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$q"}}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "setpath", Args: []*Query{&Query{Func: "$q"}, &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "getpath", Args: []*Query{&Query{Func: "$q"}}}}}, Op: OpPipe, Right: &Query{Func: "f"}}}}}}, Op: OpPipe, Right: &Query{Left: &Query{Func: "."}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeBreak, Break: "$out"}}}}}}}}}}}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "setpath", Args: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}, &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Func: "$p"}}}}}}}}}}}}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$x"}}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$x"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "delpaths", Args: []*Query{&Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$x"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}}}}}}}}}}}}}}}},
 		"normals": []*FuncDef{&FuncDef{Name: "normals", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Func: "isnormal"}}}}}}},
 		"not": []*FuncDef{&FuncDef{Name: "not", Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Func: "."}, Then: &Query{Func: "false"}, Else: &Query{Func: "true"}}}}}},
-		"nth": []*FuncDef{&FuncDef{Name: "nth", Args: []string{"$n"}, Body: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Func: "$n"}}}}}, &FuncDef{Name: "nth", Args: []string{"$n", "g"}, Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "$n"}, Op: OpLt, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, Then: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "error", Args: []*Query{&Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "nth doesn't support negative indices"}}}}}}}, Else: &Query{Term: &Term{Type: TermTypeLabel, Label: &Label{Ident: "$out", Body: &Query{Term: &Term{Type: TermTypeForeach, Foreach: &Foreach{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "g"}}, Pattern: &Pattern{Name: "$item"}, Start: &Query{Func: "$n"}, Update: &Query{Left: &Query{Func: "."}, Op: OpSub, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}, Extract: &Query{Left: &Query{Left: &Query{Left: &Query{Func: "."}, Op: OpLt, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, Op: OpOr, Right: &Query{Func: "empty"}}, Op: OpPipe, Right: &Query{Left: &Query{Func: "$item"}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeBreak, Break: "$out"}}}}}}}}}}}}}}},
+		"nth": []*FuncDef{&FuncDef{Name: "nth", Args: []string{"$n"}, Body: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Func: "$n"}}}}}, &FuncDef{Name: "nth", Args: []string{"$n", "g"}, Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "$n"}, Op: OpLt, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, Then: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "error", Args: []*Query{&Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "nth doesn't support negative indices"}}}}}}}, Else: &Query{Term: &Term{Type: TermTypeLabel, Label: &Label{Ident: "$out", Body: &Query{Term: &Term{Type: TermTypeForeach, Foreach: &Foreach{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "g"}}, Pattern: &Pattern{Name: "$item"}, Start: &Query{Left: &Query{Func: "$n"}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}, Update: &Query{Left: &Query{Func: "."}, Op: OpSub, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}, Extract: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "."}, Op: OpLe, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}, Then: &Query{Left: &Query{Func: "$item"}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeBreak, Break: "$out"}}}, Else: &Query{Func: "empty"}}}}}}}}}}}}}}},
 		"nulls": []*FuncDef{&FuncDef{Name: "nulls", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Func: "."}, Op: OpEq, Right: &Query{Func: "null"}}}}}}}},
 		"numbers": []*FuncDef{&FuncDef{Name: "numbers", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "number"}}}}}}}}}},
 		"objects": []*FuncDef{&FuncDef{Name: "objects", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "object"}}}}}}}}}},
-		"paths": []*FuncDef{&FuncDef{Name: "paths", Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "path", Args: []*Query{&Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "recurse", Args: []*Query{&Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "type"}, Op: OpPipe, Right: &Query{Left: &Query{Left: &Query{Func: "."}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "array"}}}}, Op: OpOr, Right: &Query{Left: &Query{Func: "."}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "object"}}}}}}, Then: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}, Else: &Query{Func: "empty"}}}}}}}}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Func: "length"}, Op: OpGt, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}}}}}, &FuncDef{Name: "paths", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$x"}}, Body: &Query{Left: &Query{Func: "paths"}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$p"}}, Body: &Query{Left: &Query{Func: "$x"}, Op: OpPipe, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "getpath", Args: []*Query{&Query{Func: "$p"}}}}}, Op: OpPipe, Right: &Query{Func: "f"}}}}}}}}}}}}}}}}}}}},
+		"paths": []*FuncDef{&FuncDef{Name: "paths", Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "path", Args: []*Query{&Query{Func: ".."}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Func: "."}, Op: OpNe, Right: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{}}}}}}}}}}, &FuncDef{Name: "paths", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "paths"}, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$p"}}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "getpath", Args: []*Query{&Query{Func: "$p"}}}}}, Op: OpPipe, Right: &Query{Func: "f"}}}}}}, Op: OpPipe, Right: &Query{Func: "$p"}}}}}}}}},
 		"range": []*FuncDef{&FuncDef{Name: "range", Args: []string{"$end"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_range", Args: []*Query{&Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}, &Query{Func: "$end"}, &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}}}, &FuncDef{Name: "range", Args: []string{"$start", "$end"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_range", Args: []*Query{&Query{Func: "$start"}, &Query{Func: "$end"}, &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}}}, &FuncDef{Name: "range", Args: []string{"$start", "$end", "$step"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_range", Args: []*Query{&Query{Func: "$start"}, &Query{Func: "$end"}, &Query{Func: "$step"}}}}}}},
 		"recurse": []*FuncDef{&FuncDef{Name: "recurse", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "recurse", Args: []*Query{&Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}, &Suffix{Optional: true}}}}}}}}}, &FuncDef{Name: "recurse", Args: []string{"f"}, Body: &Query{FuncDefs: []*FuncDef{&FuncDef{Name: "r", Body: &Query{Left: &Query{Func: "."}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Func: "f"}, Op: OpPipe, Right: &Query{Func: "r"}}}}}}}, Func: "r"}}, &FuncDef{Name: "recurse", Args: []string{"f", "cond"}, Body: &Query{FuncDefs: []*FuncDef{&FuncDef{Name: "r", Body: &Query{Left: &Query{Func: "."}, Op: OpComma, Right: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Func: "f"}, Op: OpPipe, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Func: "cond"}}}}}, Op: OpPipe, Right: &Query{Func: "r"}}}}}}}}, Func: "r"}}},
 		"repeat": []*FuncDef{&FuncDef{Name: "repeat", Args: []string{"f"}, Body: &Query{FuncDefs: []*FuncDef{&FuncDef{Name: "_repeat", Body: &Query{Left: &Query{Func: "f"}, Op: OpComma, Right: &Query{Func: "_repeat"}}}}, Func: "_repeat"}}},
-		"rindex": []*FuncDef{&FuncDef{Name: "rindex", Args: []string{"$x"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_rindex", Args: []*Query{&Query{Func: "$x"}}}}}}},
-		"rtrimstr": []*FuncDef{&FuncDef{Name: "rtrimstr", Args: []string{"$x"}, Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Left: &Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "string"}}}}, Op: OpAnd, Right: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Func: "$x"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "string"}}}}}}}}, Op: OpAnd, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "endswith", Args: []*Query{&Query{Func: "$x"}}}}}}, Then: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{End: &Query{Term: &Term{Type: TermTypeUnary, Unary: &Unary{Op: OpSub, Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Func: "$x"}, Op: OpPipe, Right: &Query{Func: "length"}}}}}}, IsSlice: true}}}}}}}},
 		"scalars": []*FuncDef{&FuncDef{Name: "scalars", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Func: "type"}, Op: OpPipe, Right: &Query{Left: &Query{Left: &Query{Func: "."}, Op: OpNe, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "array"}}}}, Op: OpAnd, Right: &Query{Left: &Query{Func: "."}, Op: OpNe, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "object"}}}}}}}}}}}},
-		"scan": []*FuncDef{&FuncDef{Name: "scan", Args: []string{"$re"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "scan", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "null"}}}}}}, &FuncDef{Name: "scan", Args: []string{"$re", "$flags"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "match", Args: []*Query{&Query{Func: "$re"}, &Query{Left: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "g"}}}, Op: OpAdd, Right: &Query{Func: "$flags"}}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "captures"}}}, Op: OpPipe, Right: &Query{Left: &Query{Func: "length"}, Op: OpGt, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}, Then: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "captures"}, SuffixList: []*Suffix{&Suffix{Iter: true}, &Suffix{Index: &Index{Name: "string"}}}}}}}}, Else: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "string"}}}}}}}}},
+		"scan": []*FuncDef{&FuncDef{Name: "scan", Args: []string{"$re"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "scan", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "null"}}}}}}, &FuncDef{Name: "scan", Args: []string{"$re", "$flags"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "match", Args: []*Query{&Query{Func: "$re"}, &Query{Left: &Query{Func: "$flags"}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "g"}}}}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "captures"}}}, Op: OpPipe, Right: &Query{Left: &Query{Func: "length"}, Op: OpGt, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}, Then: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "captures"}, SuffixList: []*Suffix{&Suffix{Iter: true}, &Suffix{Index: &Index{Name: "string"}}}}}}}}, Else: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "string"}}}}}}}}},
 		"select": []*FuncDef{&FuncDef{Name: "select", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Func: "f"}, Then: &Query{Func: "."}, Else: &Query{Func: "empty"}}}}}},
-		"sort": []*FuncDef{&FuncDef{Name: "sort", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "sort_by", Args: []*Query{&Query{Func: "."}}}}}}},
 		"sort_by": []*FuncDef{&FuncDef{Name: "sort_by", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_sort_by", Args: []*Query{&Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "map", Args: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Func: "f"}}}}}}}}}}}}}},
 		"splits": []*FuncDef{&FuncDef{Name: "splits", Args: []string{"$re"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "splits", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "null"}}}}}}, &FuncDef{Name: "splits", Args: []string{"$re", "$flags"}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "split", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "$flags"}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}}}}}}},
-		"startswith": []*FuncDef{&FuncDef{Name: "startswith", Args: []string{"$x"}, Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "string"}}}}, Then: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Func: "$x"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "string"}}}}}, Then: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{End: &Query{Left: &Query{Func: "$x"}, Op: OpPipe, Right: &Query{Func: "length"}}, IsSlice: true}}}, Op: OpEq, Right: &Query{Func: "$x"}}, Else: &Query{Left: &Query{Func: "$x"}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_type_error", Args: []*Query{&Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "startswith"}}}}}}}}}}}, Else: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_type_error", Args: []*Query{&Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "startswith"}}}}}}}}}}}},
 		"strings": []*FuncDef{&FuncDef{Name: "strings", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Func: "type"}, Op: OpEq, Right: &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "string"}}}}}}}}}},
-		"sub": []*FuncDef{&FuncDef{Name: "sub", Args: []string{"$re", "str"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "sub", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "str"}, &Query{Func: "null"}}}}}}, &FuncDef{Name: "sub", Args: []string{"$re", "str", "$flags"}, Body: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$in"}}, Body: &Query{FuncDefs: []*FuncDef{&FuncDef{Name: "_sub", Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "matches"}}}, Op: OpPipe, Right: &Query{Left: &Query{Func: "length"}, Op: OpGt, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}, Then: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$x"}}, Body: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "matches"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}, &Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$r"}}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$r"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Name: "captures"}}, &Suffix{Iter: true}}}}, Op: OpPipe, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "name"}}}, Op: OpNe, Right: &Query{Func: "null"}}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{&ObjectKeyVal{KeyQuery: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "name"}}}, Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "string"}}}}}}}}}}}}}}}, Op: OpPipe, Right: &Query{Left: &Query{Left: &Query{Func: "add"}, Op: OpAlt, Right: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{}}}}, Op: OpPipe, Right: &Query{Left: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{&ObjectKeyVal{Key: "string", Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$x"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Name: "string"}}}}}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$in"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$x"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Name: "offset"}}}}}, End: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$r"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Name: "offset"}}}}}, IsSlice: true}}}}}}, Op: OpAdd, Right: &Query{Func: "str"}}}}}}}, &ObjectKeyVal{Key: "offset", Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$r"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Name: "offset"}}}}}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$r"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Name: "length"}}}}}}}}}}}, &ObjectKeyVal{Key: "matches", Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$x"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Name: "matches"}}, &Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "1"}}, IsSlice: true}}}}}}}}}}}}, Op: OpPipe, Right: &Query{Func: "_sub"}}}}}}}}}}}}}}, Else: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "string"}}}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$in"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "offset"}}}, IsSlice: true}}}}}}}}}}}, Left: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{&ObjectKeyVal{Key: "string", Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeString, Str: &String{}}}}}}, &ObjectKeyVal{Key: "offset", Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}, &ObjectKeyVal{Key: "matches", Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "match", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "$flags"}}}}}}}}}}}}}}}, Op: OpPipe, Right: &Query{Func: "_sub"}}}}}}}}},
+		"sub": []*FuncDef{&FuncDef{Name: "sub", Args: []string{"$re", "str"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "sub", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "str"}, &Query{Func: "null"}}}}}}, &FuncDef{Name: "sub", Args: []string{"$re", "str", "$flags"}, Body: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$str"}}, Body: &Query{FuncDefs: []*FuncDef{&FuncDef{Name: "_sub", Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "matches"}}}, Op: OpPipe, Right: &Query{Left: &Query{Func: "length"}, Op: OpGt, Right: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}, Then: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "matches"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeUnary, Unary: &Unary{Op: OpSub, Term: &Term{Type: TermTypeNumber, Number: "1"}}}}}}, &Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$r"}}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{&ObjectKeyVal{Key: "string", Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Left: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Func: "$r"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "_capture"}, Op: OpPipe, Right: &Query{Func: "str"}}}}}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$str"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$r"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Name: "offset"}}}}}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$r"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Name: "length"}}}}}}, End: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "offset"}}}, IsSlice: true}}}}}}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "string"}}}}}}}}}, &ObjectKeyVal{Key: "offset", Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$r"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Name: "offset"}}}}}}}}, &ObjectKeyVal{Key: "matches", Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "matches"}, SuffixList: []*Suffix{&Suffix{Index: &Index{End: &Query{Term: &Term{Type: TermTypeUnary, Unary: &Unary{Op: OpSub, Term: &Term{Type: TermTypeNumber, Number: "1"}}}}, IsSlice: true}}}}}}}}}}}}, Op: OpPipe, Right: &Query{Func: "_sub"}}}}}}}, Else: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$str"}, SuffixList: []*Suffix{&Suffix{Index: &Index{End: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "offset"}}}, IsSlice: true}}}}}, Op: OpAdd, Right: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Name: "string"}}}}}}}}}, Left: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{&ObjectKeyVal{Key: "string", Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeString, Str: &String{}}}}}}, &ObjectKeyVal{Key: "matches", Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "match", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "$flags"}}}}}}}}}}}}}}}, Op: OpPipe, Right: &Query{Func: "_sub"}}}}}}}}},
 		"test": []*FuncDef{&FuncDef{Name: "test", Args: []string{"$re"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "test", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "null"}}}}}}, &FuncDef{Name: "test", Args: []string{"$re", "$flags"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_match", Args: []*Query{&Query{Func: "$re"}, &Query{Func: "$flags"}, &Query{Func: "true"}}}}}}},
-		"to_entries": []*FuncDef{&FuncDef{Name: "to_entries", Body: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "keys"}, SuffixList: []*Suffix{&Suffix{Iter: true}, &Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$k"}}, Body: &Query{Term: &Term{Type: TermTypeObject, Object: &Object{KeyVals: []*ObjectKeyVal{&ObjectKeyVal{Key: "key", Val: &ObjectVal{Queries: []*Query{&Query{Func: "$k"}}}}, &ObjectKeyVal{Key: "value", Val: &ObjectVal{Queries: []*Query{&Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Func: "$k"}}}}}}}}}}}}}}}}}}}}},
 		"todate": []*FuncDef{&FuncDef{Name: "todate", Body: &Query{Func: "todateiso8601"}}},
 		"todateiso8601": []*FuncDef{&FuncDef{Name: "todateiso8601", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "strftime", Args: []*Query{&Query{Term: &Term{Type: TermTypeString, Str: &String{Str: "%Y-%m-%dT%H:%M:%SZ"}}}}}}}}},
 		"tostream": []*FuncDef{&FuncDef{Name: "tostream", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "path", Args: []*Query{&Query{FuncDefs: []*FuncDef{&FuncDef{Name: "r", Body: &Query{Left: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}, &Suffix{Optional: true}}}}, Op: OpPipe, Right: &Query{Func: "r"}}}}, Op: OpComma, Right: &Query{Func: "."}}}}, Func: "r"}}}, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$p"}}, Body: &Query{Left: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "getpath", Args: []*Query{&Query{Func: "$p"}}}}}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeReduce, Reduce: &Reduce{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "path", Args: []*Query{&Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Iter: true}, &Suffix{Optional: true}}}}}}}, Pattern: &Pattern{Name: "$q"}, Start: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Func: "$p"}, Op: OpComma, Right: &Query{Func: "."}}}}}, Update: &Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Left: &Query{Func: "$p"}, Op: OpAdd, Right: &Query{Func: "$q"}}}}}}}}}}}}}}}},
-		"truncate_stream": []*FuncDef{&FuncDef{Name: "truncate_stream", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$n"}}, Body: &Query{Left: &Query{Func: "null"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "f"}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$input"}}, Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Term: &Term{Type: TermTypeQuery, Query: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}, Op: OpPipe, Right: &Query{Func: "length"}}}}, Op: OpGt, Right: &Query{Func: "$n"}}, Then: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "setpath", Args: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}, &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "$input"}, SuffixList: []*Suffix{&Suffix{Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}, &Suffix{Index: &Index{Start: &Query{Func: "$n"}, IsSlice: true}}}}}}}}}, Else: &Query{Func: "empty"}}}}}}}}}}}}}}}}}},
-		"unique": []*FuncDef{&FuncDef{Name: "unique", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "unique_by", Args: []*Query{&Query{Func: "."}}}}}}},
+		"truncate_stream": []*FuncDef{&FuncDef{Name: "truncate_stream", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{&Suffix{Bind: &Bind{Patterns: []*Pattern{&Pattern{Name: "$n"}}, Body: &Query{Left: &Query{Func: "null"}, Op: OpPipe, Right: &Query{Left: &Query{Func: "f"}, Op: OpPipe, Right: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}, Op: OpPipe, Right: &Query{Left: &Query{Func: "length"}, Op: OpGt, Right: &Query{Func: "$n"}}}, Then: &Query{Left: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Term: &Term{Type: TermTypeNumber, Number: "0"}}}}}, Op: OpModify, Right: &Query{Term: &Term{Type: TermTypeIndex, Index: &Index{Start: &Query{Func: "$n"}, IsSlice: true}}}}, Else: &Query{Func: "empty"}}}}}}}}}}}}},
 		"unique_by": []*FuncDef{&FuncDef{Name: "unique_by", Args: []string{"f"}, Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "_unique_by", Args: []*Query{&Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "map", Args: []*Query{&Query{Term: &Term{Type: TermTypeArray, Array: &Array{Query: &Query{Func: "f"}}}}}}}}}}}}}},
 		"until": []*FuncDef{&FuncDef{Name: "until", Args: []string{"cond", "next"}, Body: &Query{FuncDefs: []*FuncDef{&FuncDef{Name: "_until", Body: &Query{Term: &Term{Type: TermTypeIf, If: &If{Cond: &Query{Func: "cond"}, Then: &Query{Func: "."}, Else: &Query{Left: &Query{Func: "next"}, Op: OpPipe, Right: &Query{Func: "_until"}}}}}}}, Func: "_until"}}},
 		"values": []*FuncDef{&FuncDef{Name: "values", Body: &Query{Term: &Term{Type: TermTypeFunc, Func: &Func{Name: "select", Args: []*Query{&Query{Left: &Query{Func: "."}, Op: OpNe, Right: &Query{Func: "null"}}}}}}}},
diff --git a/builtin.jq b/builtin.jq
index b6a9e1d..491f57f 100644
--- a/builtin.jq
+++ b/builtin.jq
@@ -1,10 +1,6 @@
 def not: if . then false else true end;
 def in(xs): . as $x | xs | has($x);
 def map(f): [.[] | f];
-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 select(f): if f then . else empty end;
 def recurse: recurse(.[]?);
@@ -24,21 +20,10 @@ 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 _flatten($x):
-  map(if type == "array" and $x != 0 then _flatten($x - 1) else [.] end) | add;
-def flatten($x):
-  if $x < 0
-  then error("flatten depth must not be negative")
-  else _flatten($x) // [] end;
-def flatten: _flatten(-1) // [];
-def min: min_by(.);
 def min_by(f): _min_by(map([f]));
-def max: max_by(.);
 def max_by(f): _max_by(map([f]));
-def sort: sort_by(.);
 def sort_by(f): _sort_by(map([f]));
 def group_by(f): _group_by(map([f]));
-def unique: unique_by(.);
 def unique_by(f): _unique_by(map([f]));
 
 def arrays: select(type == "array");
@@ -54,49 +39,9 @@ def values: select(. != null);
 def scalars: select(type | . != "array" and . != "object");
 def leaf_paths: paths(scalars);
 
-def indices($x): _indices($x);
-def index($x): _lindex($x);
-def rindex($x): _rindex($x);
 def inside(xs): . as $x | xs | contains($x);
-def startswith($x):
-  if type == "string" then
-    if $x|type == "string" then
-      .[:$x | length] == $x
-    else
-      $x | _type_error("startswith")
-    end
-  else
-    _type_error("startswith")
-  end;
-def endswith($x):
-  if type == "string" then
-    if $x|type == "string" then
-      .[- ($x | length):] == $x
-    else
-      $x | _type_error("endswith")
-    end
-  else
-    _type_error("endswith")
-  end;
-def ltrimstr($x):
-  if type == "string" and ($x|type == "string") and startswith($x) then
-    .[$x | length:]
-  end;
-def rtrimstr($x):
-  if type == "string" and ($x|type == "string") and endswith($x) then
-    .[:- ($x | length)]
-  end;
-
-def combinations:
-  if length == 0 then
-    []
-  else
-    .[0][] as $x | .[1:] | combinations as $y | [$x] + $y
-  end;
-def combinations(n):
-  . as $dot | [range(n) | $dot] | combinations;
-def join($x):
-  if type != "array" then [.[]] end | _join($x);
+def combinations: if length == 0 then [] else .[0][] as $x | [$x] + (.[1:] | combinations) end;
+def combinations(n): [limit(n; repeat(.))] | combinations;
 def ascii_downcase:
   explode | map(if 65 <= . and . <= 90 then . + 32 end) | implode;
 def ascii_upcase:
@@ -110,17 +55,17 @@ def first(g): label $out | g | ., break $out;
 def last: .[-1];
 def last(g): reduce g as $item (null; $item);
 def isempty(g): label $out | (g | false, break $out), true;
-def all: all(.[]; .);
+def all: all(.);
 def all(y): all(.[]; y);
-def all(g; y): isempty(g|y and empty);
-def any: any(.[]; .);
+def all(g; y): isempty(g | select(y | not));
+def any: any(.);
 def any(y): any(.[]; y);
-def any(g; y): isempty(g|y or empty) | not;
+def any(g; y): isempty(g | select(y)) | not;
 def limit($n; g):
   if $n > 0 then
     label $out
       | foreach g as $item
-        ($n; .-1; $item, if . <= 0 then break $out else empty end)
+        ($n; . - 1; $item, if . <= 0 then break $out else empty end)
   elif $n == 0 then
     empty
   else
@@ -133,12 +78,11 @@ def nth($n; g):
   else
     label $out
       | foreach g as $item
-        ($n; .-1; . < 0 or empty | $item, break $out)
+        ($n + 1; . - 1; if . <= 0 then $item, break $out else empty end)
   end;
 
 def truncate_stream(f):
-  . as $n | null | f | . as $input
-    | if (.[0] | length) > $n then setpath([0]; $input[0][$n:]) else empty end;
+  . as $n | null | f | if .[0] | length > $n then .[0] |= .[$n:] else empty end;
 def fromstream(f):
   { x: null, e: false } as $init
     | foreach f as $i
@@ -161,11 +105,8 @@ def _modify(ps; f):
       | . as $x | $x[0] | delpaths($x[1]);
 def map_values(f): .[] |= f;
 def del(f): delpaths([path(f)]);
-def paths:
-  path(recurse(if type | . == "array" or . == "object" then .[] else empty end))
-    | select(length > 0);
-def paths(f):
-  . as $x | paths | select(. as $p | $x | getpath($p) | f);
+def paths: path(..) | select(. != []);
+def paths(f): paths as $p | select(getpath($p) | f) | $p;
 
 def fromdateiso8601: strptime("%Y-%m-%dT%H:%M:%S%z") | mktime;
 def todateiso8601: strftime("%Y-%m-%dT%H:%M:%SZ");
@@ -177,35 +118,30 @@ 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)
-    | [.captures[] | select(.name != null) | { (.name): .string }]
-    | add // {};
+def capture($re; $flags): match($re; $flags) | _capture;
 def scan($re): scan($re; null);
 def scan($re; $flags):
-  match($re; "g" + $flags)
+  match($re; $flags + "g")
     | if .captures|length > 0 then [.captures[].string] else .string end;
 def splits($re): splits($re; null);
 def splits($re; $flags): split($re; $flags) | .[];
 def sub($re; str): sub($re; str; null);
 def sub($re; str; $flags):
-  . as $in
+  . as $str
     | def _sub:
         if .matches|length > 0
         then
-          . as $x | .matches[0] as $r
-            | [$r.captures[] | select(.name != null) | { (.name): .string }]
-            | add // {}
+          .matches[-1] as $r
             | {
-                string: ($x.string + $in[$x.offset:$r.offset] + str),
-                offset: ($r.offset + $r.length),
-                matches: $x.matches[1:]
+                string: (($r | _capture | str) + $str[$r.offset+$r.length:.offset] + .string),
+                offset: $r.offset,
+                matches: .matches[:-1],
               }
             | _sub
         else
-          .string + $in[.offset:]
+          $str[:.offset] + .string
         end;
-  { string: "", offset: 0, matches: [match($re; $flags)] } | _sub;
+  { string: "", matches: [match($re; $flags)] } | _sub;
 def gsub($re; str): sub($re; str; "g");
 def gsub($re; str; $flags): sub($re; str; $flags + "g");
 
diff --git a/cli/encoder.go b/cli/encoder.go
index 5ff6de0..c8c94fa 100644
--- a/cli/encoder.go
+++ b/cli/encoder.go
@@ -56,7 +56,7 @@ func (e *encoder) encode(v interface{}) {
 	case map[string]interface{}:
 		e.encodeMap(v)
 	default:
-		panic(fmt.Sprintf("invalid value: %v", v))
+		panic(fmt.Sprintf("invalid type: %T (%v)", v, v))
 	}
 	if e.w.Len() > 8*1024 {
 		e.out.Write(e.w.Bytes())
@@ -99,30 +99,31 @@ func (e *encoder) encodeString(s string, color []byte) {
 	start := 0
 	for i := 0; i < len(s); {
 		if b := s[i]; b < utf8.RuneSelf {
-			if ']' <= b && b <= '~' || '#' <= b && b <= '[' || b == ' ' || b == '!' {
+			if ' ' <= b && b <= '~' && b != '"' && b != '\\' {
 				i++
 				continue
 			}
 			if start < i {
 				e.w.WriteString(s[start:i])
 			}
-			e.w.WriteByte('\\')
 			switch b {
-			case '\\', '"':
-				e.w.WriteByte(b)
+			case '"':
+				e.w.WriteString(`\"`)
+			case '\\':
+				e.w.WriteString(`\\`)
 			case '\b':
-				e.w.WriteByte('b')
+				e.w.WriteString(`\b`)
 			case '\f':
-				e.w.WriteByte('f')
+				e.w.WriteString(`\f`)
 			case '\n':
-				e.w.WriteByte('n')
+				e.w.WriteString(`\n`)
 			case '\r':
-				e.w.WriteByte('r')
+				e.w.WriteString(`\r`)
 			case '\t':
-				e.w.WriteByte('t')
+				e.w.WriteString(`\t`)
 			default:
 				const hex = "0123456789abcdef"
-				e.w.WriteString("u00")
+				e.w.WriteString(`\u00`)
 				e.w.WriteByte(hex[b>>4])
 				e.w.WriteByte(hex[b&0xF])
 			}
diff --git a/cli/error.go b/cli/error.go
index f7b952e..5f44028 100644
--- a/cli/error.go
+++ b/cli/error.go
@@ -3,6 +3,7 @@ package cli
 import (
 	"encoding/json"
 	"fmt"
+	"io"
 	"strconv"
 	"strings"
 	"unicode/utf8"
@@ -75,21 +76,17 @@ type queryParseError struct {
 }
 
 func (err *queryParseError) Error() string {
-	if er, ok := err.err.(interface{ Token() (string, int) }); ok {
-		_, offset := er.Token()
-		linestr, line, col := getLineByOffset(err.contents, offset)
-		var fname, prefix string
-		if !strings.ContainsAny(err.contents, "\n\r") && strings.HasPrefix(err.fname, "<arg>") {
-			fname = err.contents
-		} else {
-			fname = err.fname + ":" + strconv.Itoa(line)
-			prefix = strconv.Itoa(line) + " | "
+	if e, ok := err.err.(interface{ Token() (string, int) }); ok {
+		_, offset := e.Token()
+		linestr, line, column := getLineByOffset(err.contents, offset)
+		if strings.HasPrefix(err.fname, "<arg>") && !containsNewline(err.contents) {
+			return fmt.Sprintf("invalid %s: %s\n    %s\n%s    ^  %s",
+				err.typ, err.contents, linestr, strings.Repeat(" ", column), err.err)
 		}
-		return "invalid " + err.typ + ": " + fname + "\n" +
-			"    " + prefix + linestr + "\n" +
-			"    " + strings.Repeat(" ", len(prefix)+col) + "^  " + err.err.Error()
+		return fmt.Sprintf("invalid %s: %s:%d\n%s  %s",
+			err.typ, err.fname, line, formatLineInfo(linestr, line, column), err.err)
 	}
-	return "invalid " + err.typ + ": " + err.fname + ": " + err.err.Error()
+	return fmt.Sprintf("invalid %s: %s: %s", err.typ, err.fname, err.err)
 }
 
 func (err *queryParseError) ExitCode() int {
@@ -103,28 +100,19 @@ type jsonParseError struct {
 }
 
 func (err *jsonParseError) Error() string {
-	var prefix, linestr string
-	var line, col int
-	fname, errmsg := err.fname, err.err.Error()
-	if errmsg == "unexpected EOF" {
-		linestr = strings.TrimRight(err.contents, "\n\r")
-		if i := strings.LastIndexAny(linestr, "\n\r"); i >= 0 {
-			linestr = linestr[i:]
-		}
-		col = runewidth.StringWidth(linestr)
-	} else if er, ok := err.err.(*json.SyntaxError); ok {
-		linestr, line, col = getLineByOffset(
-			trimLastInvalidRune(err.contents), int(er.Offset),
-		)
-		if i := strings.IndexAny(err.contents, "\n\r"); i >= 0 && i < len(err.contents)-1 {
-			line += err.line
-			fname += ":" + strconv.Itoa(line)
-			prefix = strconv.Itoa(line) + " | "
-		}
+	var offset int
+	if err.err == io.ErrUnexpectedEOF {
+		offset = len(err.contents) + 1
+	} else if e, ok := err.err.(*json.SyntaxError); ok {
+		offset = int(e.Offset)
+	}
+	linestr, line, column := getLineByOffset(err.contents, offset)
+	if line += err.line; line > 1 {
+		return fmt.Sprintf("invalid json: %s:%d\n%s  %s",
+			err.fname, line, formatLineInfo(linestr, line, column), err.err)
 	}
-	return "invalid json: " + fname + "\n" +
-		"    " + prefix + linestr + "\n" +
-		"    " + strings.Repeat(" ", len(prefix)+col) + "^  " + errmsg
+	return fmt.Sprintf("invalid json: %s\n    %s\n%s    ^  %s",
+		err.fname, linestr, strings.Repeat(" ", column), err.err)
 }
 
 type yamlParseError struct {
@@ -144,109 +132,131 @@ func (err *yamlParseError) Error() string {
 		}
 		msg = strings.Split(msg, "\n")[1]
 		fmt.Sscanf(msg, " line %d: ", &line)
-		if line > 0 {
-			msg = msg[2+strings.IndexRune(msg, ':'):] // trim "line N:"
-		} else {
+		if line == 0 {
 			return "invalid yaml: " + err.fname
 		}
+		msg = msg[2+strings.IndexRune(msg, ':'):] // trim "line N:"
 	}
-	var ss strings.Builder
-	var i, j int
-	var cr bool
-	for _, r := range trimLastInvalidRune(err.contents) {
-		i += len(string(r))
-		if r == '\n' || r == '\r' {
-			if !cr || r != '\n' {
-				j++
-			}
-			cr = r == '\r'
-			if j == line {
-				break
-			}
-			ss.Reset()
-		} else {
-			cr = false
-			ss.WriteRune(r)
-		}
-	}
-	linestr := strconv.Itoa(line)
-	return "invalid yaml: " + err.fname + ":" + linestr + "\n" +
-		"    " + linestr + " | " + ss.String() + "\n" +
-		"    " + strings.Repeat(" ", len(linestr)) + "   ^  " + msg
-}
-
-func getLineByOffset(str string, offset int) (string, int, int) {
-	var pos, col int
-	var cr bool
-	line, total := 1, len(str)
-	for offset > 128 && offset <= total {
-		diff := offset / 2
-		for i := 0; i < utf8.UTFMax; i++ {
-			if r, _ := utf8.DecodeLastRuneInString(str[:diff+i]); r != utf8.RuneError {
-				diff += i
-				break
-			}
-		}
-		for _, r := range str[:diff] {
-			if r == '\n' || r == '\r' {
-				if !cr || r != '\n' {
-					line++
-				}
-				cr = r == '\r'
-			}
+	linestr := getLineByLine(err.contents, line)
+	return fmt.Sprintf("invalid yaml: %s:%d\n%s  %s",
+		err.fname, line, formatLineInfo(linestr, line, 0), msg)
+}
+
+func getLineByOffset(str string, offset int) (linestr string, line, column int) {
+	ss := &stringScanner{str, 0}
+	for {
+		str, start, ok := ss.next()
+		if !ok {
+			offset -= start
+			break
 		}
-		str = str[diff:]
-		offset -= diff
-	}
-	var ss strings.Builder
-	for _, r := range str {
-		if k := utf8.RuneLen(r); k > 0 {
-			pos += k
-		} else {
-			pos += len(string(r))
+		line++
+		linestr = str
+		if ss.offset >= offset {
+			offset -= start
+			break
 		}
-		if pos < offset {
-			col += runewidth.RuneWidth(r)
+	}
+	if offset > len(linestr) {
+		offset = len(linestr)
+	} else if offset > 0 {
+		offset--
+	} else {
+		offset = 0
+	}
+	if offset > 48 {
+		skip := len(trimLastInvalidRune(linestr[:offset-48]))
+		linestr = linestr[skip:]
+		offset -= skip
+	}
+	if len(linestr) > 64 {
+		linestr = linestr[:64]
+	}
+	linestr = trimLastInvalidRune(linestr)
+	if offset >= len(linestr) {
+		offset = len(linestr)
+	} else {
+		offset = len(trimLastInvalidRune(linestr[:offset]))
+	}
+	column = runewidth.StringWidth(linestr[:offset])
+	return
+}
+
+func getLineByLine(str string, line int) (linestr string) {
+	ss := &stringScanner{str, 0}
+	for {
+		str, _, ok := ss.next()
+		if !ok {
+			break
 		}
-		if r == '\n' || r == '\r' {
-			if pos >= offset {
-				break
-			} else if pos < total {
-				col = 0
-				if !cr || r != '\n' {
-					line++
-				}
-				cr = r == '\r'
-				ss.Reset()
-			}
-		} else {
-			cr = false
-			ss.WriteRune(r)
-			if ss.Len() > 64 {
-				if pos > offset {
-					break
-				}
-				s, i := ss.String(), 48
-				ss.Reset()
-				for j := 0; j < utf8.UTFMax; j++ {
-					if r, _ := utf8.DecodeRuneInString(s[i+j:]); r != utf8.RuneError {
-						i += j
-						break
-					}
-				}
-				col -= runewidth.StringWidth(s[:i])
-				ss.WriteString(s[i:])
-			}
+		if line--; line == 0 {
+			linestr = str
+			break
 		}
 	}
-	return ss.String(), line, col
+	if len(linestr) > 64 {
+		linestr = trimLastInvalidRune(linestr[:64])
+	}
+	return
 }
 
 func trimLastInvalidRune(s string) string {
-	for i := 0; i < utf8.UTFMax && i < len(s); i++ {
-		if r, _ := utf8.DecodeLastRuneInString(s[:len(s)-i]); r != utf8.RuneError {
-			return s[:len(s)-i]
+	for i := len(s) - 1; i >= 0 && i > len(s)-utf8.UTFMax; i-- {
+		if b := s[i]; b < utf8.RuneSelf {
+			return s[:i+1]
+		} else if utf8.RuneStart(b) {
+			if r, _ := utf8.DecodeRuneInString(s[i:]); r == utf8.RuneError {
+				return s[:i]
+			}
+			break
 		}
 	}
 	return s
 }
+
+func formatLineInfo(linestr string, line, column int) string {
+	l := strconv.Itoa(line)
+	return "    " + l + " | " + linestr + "\n" +
+		strings.Repeat(" ", len(l)+column) + "       ^"
+}
+
+type stringScanner struct {
+	str    string
+	offset int
+}
+
+func (ss *stringScanner) next() (line string, start int, ok bool) {
+	if ss.offset == len(ss.str) {
+		return
+	}
+	start, ok = ss.offset, true
+	line = ss.str[start:]
+	i := indexNewline(line)
+	if i < 0 {
+		ss.offset = len(ss.str)
+		return
+	}
+	line = line[:i]
+	if strings.HasPrefix(ss.str[start+i:], "\r\n") {
+		i++
+	}
+	ss.offset += i + 1
+	return
+}
+
+// Faster than strings.ContainsAny(str, "\r\n").
+func containsNewline(str string) bool {
+	return strings.IndexByte(str, '\n') >= 0 ||
+		strings.IndexByte(str, '\r') >= 0
+}
+
+// Faster than strings.IndexAny(str, "\r\n").
+func indexNewline(str string) (i int) {
+	if i = strings.IndexByte(str, '\n'); i >= 0 {
+		str = str[:i]
+	}
+	if j := strings.IndexByte(str, '\r'); j >= 0 {
+		i = j
+	}
+	return
+}
diff --git a/cli/error_test.go b/cli/error_test.go
new file mode 100644
index 0000000..6780162
--- /dev/null
+++ b/cli/error_test.go
@@ -0,0 +1,243 @@
+package cli
+
+import (
+	"fmt"
+	"strings"
+	"testing"
+)
+
+func generateString(size int) string {
+	var sb strings.Builder
+	sb.Grow(size)
+	for i, j := 0, 0; i < size; i, j = i+1, (i+j)%256 {
+		sb.WriteByte(byte(j%10 | '0'))
+	}
+	return sb.String()
+}
+
+func TestGetLineByOffset(t *testing.T) {
+	numbers := generateString(500)
+	var testCases = []struct {
+		str          string
+		offset       int
+		linestr      string
+		line, column int
+	}{
+		{
+			"", 0,
+			"", 0, 0,
+		},
+		{
+			"abc", -1,
+			"abc", 1, 0,
+		},
+		{
+			"abc", 0,
+			"abc", 1, 0,
+		},
+		{
+			"abc", 1,
+			"abc", 1, 0,
+		},
+		{
+			"abc", 2,
+			"abc", 1, 1,
+		},
+		{
+			"abc", 3,
+			"abc", 1, 2,
+		},
+		{
+			"abc", 4,
+			"abc", 1, 3,
+		},
+		{
+			"abc\ndef\nghi", 4,
+			"abc", 1, 3,
+		},
+		{
+			"abc\rdef\rghi", 4,
+			"abc", 1, 3,
+		},
+		{
+			"abc\r\ndef\r\nghi", 4,
+			"abc", 1, 3,
+		},
+		{
+			"abc\ndef\nghi", 5,
+			"def", 2, 0,
+		},
+		{
+			"abc\rdef\rghi", 5,
+			"def", 2, 0,
+		},
+		{
+			"abc\r\ndef\r\nghi", 6,
+			"def", 2, 0,
+		},
+		{
+			"abc\ndef\nghi", 7,
+			"def", 2, 2,
+		},
+		{
+			"abc\ndef\nghi", 8,
+			"def", 2, 3,
+		},
+		{
+			"abc\ndef\nghi", 9,
+			"ghi", 3, 0,
+		},
+		{
+			"abc\ndef\nghi", 12,
+			"ghi", 3, 3,
+		},
+		{
+			"abc\ndef\nghi", 13,
+			"ghi", 3, 3,
+		},
+		{
+			"abc\n012\nghi", 5,
+			"012", 2, 0,
+		},
+		{
+			"abc\n012\nghi", 6,
+			"012", 2, 0,
+		},
+		{
+			"abc\n012\nghi", 7,
+			"012", 2, 0,
+		},
+		{
+			"abc\n012\nghi", 8,
+			"012", 2, 2,
+		},
+		{
+			"abc\n012\nghi", 9,
+			"012", 2, 2,
+		},
+		{
+			"abc\n012\nghi", 10,
+			"012", 2, 2,
+		},
+		{
+			"abc\n012\nghi", 11,
+			"012", 2, 4,
+		},
+		{
+			"abc\ndef\xef\xbc\nghi", 10,
+			"def", 2, 3,
+		},
+		{
+			numbers, 0,
+			numbers[:64], 1, 0,
+		},
+		{
+			numbers, 30,
+			numbers[:64], 1, 29,
+		},
+		{
+			numbers, 100,
+			numbers[51:115], 1, 48,
+		},
+		{
+			numbers, 400,
+			numbers[351:415], 1, 48,
+		},
+		{
+			numbers, 450,
+			numbers[401:465], 1, 48,
+		},
+		{
+			numbers, 500,
+			numbers[451:], 1, 48,
+		},
+	}
+	for _, tc := range testCases {
+		var name string
+		if len(tc.str) > 20 {
+			name = tc.str[:20] + "..."
+		} else {
+			name = tc.str
+		}
+		t.Run(fmt.Sprintf("%q,%d", name, tc.offset), func(t *testing.T) {
+			linestr, line, column := getLineByOffset(tc.str, tc.offset)
+			if linestr != tc.linestr || line != tc.line || column != tc.column {
+				t.Errorf("getLineByOffset(%q, %d):\n"+
+					"     got: %q, %d, %d\n"+
+					"expected: %q, %d, %d", tc.str, tc.offset,
+					linestr, line, column, tc.linestr, tc.line, tc.column)
+			}
+		})
+	}
+}
+
+func TestGetLineByLine(t *testing.T) {
+	var testCases = []struct {
+		str     string
+		line    int
+		linestr string
+	}{
+		{
+			"", 0,
+			"",
+		},
+		{
+			"abc", -1,
+			"",
+		},
+		{
+			"abc", 0,
+			"",
+		},
+		{
+			"abc", 1,
+			"abc",
+		},
+		{
+			"abc\n", 1,
+			"abc",
+		},
+		{
+			"abc", 2,
+			"",
+		},
+		{
+			"abc\n", 2,
+			"",
+		},
+		{
+			"abc\ndef\nghi", 1,
+			"abc",
+		},
+		{
+			"abc\ndef\nghi", 2,
+			"def",
+		},
+		{
+			"abc\rdef\rghi", 2,
+			"def",
+		},
+		{
+			"abc\r\ndef\r\nghi", 2,
+			"def",
+		},
+		{
+			"abc\ndef\nghi", 3,
+			"ghi",
+		},
+		{
+			"abc\ndef\nghi", 4,
+			"",
+		},
+	}
+	for _, tc := range testCases {
+		t.Run(fmt.Sprintf("%q,%d", tc.str, tc.line), func(t *testing.T) {
+			linestr := getLineByLine(tc.str, tc.line)
+			if linestr != tc.linestr {
+				t.Errorf("getLineByLine(%q, %d):\n"+
+					"     got: %q\n"+
+					"expected: %q", tc.str, tc.line, linestr, tc.linestr)
+			}
+		})
+	}
+}
diff --git a/cli/stream.go b/cli/stream.go
index 7a258cd..e647711 100644
--- a/cli/stream.go
+++ b/cli/stream.go
@@ -1,6 +1,9 @@
 package cli
 
-import "encoding/json"
+import (
+	"encoding/json"
+	"io"
+)
 
 type jsonStream struct {
 	dec    *json.Decoder
@@ -44,6 +47,9 @@ func (s *jsonStream) next() (interface{}, error) {
 	for {
 		token, err := s.dec.Token()
 		if err != nil {
+			if err == io.EOF && s.states[len(s.states)-1] != jsonStateTopValue {
+				err = io.ErrUnexpectedEOF
+			}
 			return nil, err
 		}
 		if d, ok := token.(json.Delim); ok {
diff --git a/cli/test.yaml b/cli/test.yaml
index 98ef129..20346f2 100644
--- a/cli/test.yaml
+++ b/cli/test.yaml
@@ -49,62 +49,209 @@
 - name: string input
   args:
     - '.'
-  input: '"Hello, world!\r\n\t\f\b\uff06"'
+  input: '"Hello, world! \r\n\t\f\b\"\\\/\uff06"'
   expected: |
-    "Hello, world!\r\n\t\f\b&"
+    "Hello, world! \r\n\t\f\b\"\\/&"
 
 - name: string query
   args:
-    - '" Hello, world! \r\n\t\f\b\uff10 "'
-  input: '0'
+    - '" Hello, world! \r\n\t\f\b\"\\\/\uff10 "'
+  input: 'null'
   expected: |
-    " Hello, world! \r\n\t\f\b0 "
+    " Hello, world! \r\n\t\f\b\"\\/0 "
 
 - name: string query including newlines
   args:
     - "\"a\n\\(\"\nb\nc\n\")\nd\n\""
-  input: '0'
+  input: 'null'
   expected: |
     "a\n\nb\nc\n\nd\n"
 
+- name: string query including control characters
+  args:
+    - "\"\x01\x07\x0f\\n\", \"\x7f\\n\""
+  input: 'null'
+  expected: |
+    "\u0001\u0007\u000f\n"
+    "\u007f\n"
+
+- name: string query including surrogate pairs
+  args:
+    - '"\ud83d\ude04" | length, utf8bytelength, explode[]'
+  input: 'null'
+  expected: |
+    1
+    4
+    128516
+
 - name: string query error
   args:
     - '. + "foo'
-  input: '0'
+  input: 'null'
   error: |
     invalid query: . + "foo
         . + "foo
-            ^  invalid token "foo
+                ^  unterminated string literal
   exit_code: 3
 
 - name: string query error
   args:
     - '"foo\,bar"'
-  input: '0'
+  input: 'null'
   error: |
     invalid query: "foo\,bar"
         "foo\,bar"
-            ^  invalid token "\,"
+            ^  invalid escape sequence "\," in string literal
   exit_code: 3
 
 - name: string query error
   args:
-    - '"\u "'
-  input: '0'
+    - '"\u"'
+  input: 'null'
+  error: |
+    invalid query: "\u"
+        "\u"
+         ^  invalid escape sequence "\u" in string literal
+  exit_code: 3
+
+- name: string query error
+  args:
+    - "\"\n\\u\n\""
+  input: 'null'
+  error: |
+    invalid query: <arg>:2
+        2 | \u
+            ^  invalid escape sequence "\u" in string literal
+  exit_code: 3
+
+- name: string query error
+  args:
+    - '"\u'
+  input: 'null'
+  error: |
+    invalid query: "\u
+        "\u
+         ^  invalid escape sequence "\u" in string literal
+  exit_code: 3
+
+- name: string query error
+  args:
+    - '"\'
+  input: 'null'
+  error: |
+    invalid query: "\
+        "\
+          ^  unterminated string literal
+  exit_code: 3
+
+- name: string query error
+  args:
+    - '"\"'
+  input: 'null'
+  error: |
+    invalid query: "\"
+        "\"
+           ^  unterminated string literal
+  exit_code: 3
+
+- name: string query error
+  args:
+    - '"\u````"'
+  input: 'null'
+  error: |
+    invalid query: "\u````"
+        "\u````"
+         ^  invalid escape sequence "\u" in string literal
+  exit_code: 3
+
+- name: string query error
+  args:
+    - '"\uAA\uAA"'
+  input: 'null'
+  error: |
+    invalid query: "\uAA\uAA"
+        "\uAA\uAA"
+         ^  invalid escape sequence "\uAA" in string literal
+  exit_code: 3
+
+- name: string query error
+  args:
+    - '"\uAA@AA"'
+  input: 'null'
+  error: |
+    invalid query: "\uAA@AA"
+        "\uAA@AA"
+         ^  invalid escape sequence "\uAA" in string literal
+  exit_code: 3
+
+- name: string query error
+  args:
+    - '"\uAAGA"'
+  input: 'null'
+  error: |
+    invalid query: "\uAAGA"
+        "\uAAGA"
+         ^  invalid escape sequence "\uAA" in string literal
+  exit_code: 3
+
+- name: string query error
+  args:
+    - '"\ufffg"'
+  input: 'null'
+  error: |
+    invalid query: "\ufffg"
+        "\ufffg"
+         ^  invalid escape sequence "\ufff" in string literal
+  exit_code: 3
+
+- name: string query error
+  args:
+    - '"0\u00:00"'
+  input: 'null'
+  error: |
+    invalid query: "0\u00:00"
+        "0\u00:00"
+          ^  invalid escape sequence "\u00" in string literal
+  exit_code: 3
+
+- name: string query error
+  args:
+    - '"0\u0000\u000/0"'
+  input: 'null'
   error: |
-    invalid query: "\u "
-        "\u "
-        ^  invalid token "\u "
+    invalid query: "0\u0000\u000/0"
+        "0\u0000\u000/0"
+                ^  invalid escape sequence "\u000" in string literal
   exit_code: 3
 
 - name: string query error
   args:
     - '"\(1) \x "'
-  input: '0'
+  input: 'null'
   error: |
     invalid query: "\(1) \x "
         "\(1) \x "
-             ^  invalid token " \x "
+              ^  invalid escape sequence "\x" in string literal
+  exit_code: 3
+
+- name: string query error
+  args:
+    - '"\a"'
+  input: 'null'
+  error: |
+    invalid query: "\a"
+        "\a"
+         ^  invalid escape sequence "\a" in string literal
+  exit_code: 3
+
+- name: string query error
+  args:
+    - '"\u\('
+  input: 'null'
+  error: |
+    invalid query: "\u\(
+        "\u\(
+         ^  invalid escape sequence "\u" in string literal
   exit_code: 3
 
 - name: object input
@@ -121,21 +268,21 @@
       "foo\\u0000\\t\\n\\r\\u001f !\"#$/09:;<>?@AZ[\\\\]^_`az{|}~\\u007f": "<\\t\\n\\r>"
     }
 
-- name: object index
+- name: object indexing
   args:
     - '.foo'
   input: '{"foo": 128}'
   expected: |
     128
 
-- name: object index with large number value
+- name: object indexing with large number value
   args:
     - '.foo'
   input: '{"foo": 4722366482869645213696}'
   expected: |
     4722366482869645213696
 
-- name: object index by keywords
+- name: object indexing by keywords
   args:
     - '.and,.or,.try'
   input: '{"and":1,"or":2,"try":3}'
@@ -144,36 +291,40 @@
     2
     3
 
-- name: object index by brackets
+- name: object indexing by brackets
   args:
     - '.["foo"]'
   input: '{"foo": 128}'
   expected: |
     128
 
-- name: object index by string
+- name: object indexing by string
   args:
-    - '."2\(.foo[])3"'
+    - '."foo", ."2\(.foo[])3"'
   input: '{"foo":[1,2],"213":3,"223":6}'
   expected: |
+    [
+      1,
+      2
+    ]
     3
     6
 
-- name: object index by query
+- name: object indexing by query
   args:
     - '.c[.a + .b]'
   input: '{ "a": "b", "b": "c", "c": {"bc": 128} }'
   expected: |
     128
 
-- name: object nested index by query
+- name: object nested indexing by query
   args:
     - '.d[.a][.b][.c]'
   input: '{ "a": "b", "b": "c", "c": "d", "d": { "b": { "c": { "d": 128 } } } }'
   expected: |
     128
 
-- name: object index by iterator after iterator
+- name: object indexing by iterator after iterator
   args:
     - '.c[][.a[] + .b[]]'
   input: '{ "a": ["a", "b"], "b": ["c", "d"], "c": [{"ac": 1, "bc": 2, "ad": 3, "bd": 4}, {"ac": 5, "bc": 6, "ad": 7, "bd": 8}] }'
@@ -187,7 +338,7 @@
     4
     8
 
-- name: object index by string iterator after iterator
+- name: object indexing by string iterator after iterator
   args:
     - '.c[]."\(.a[])"'
   input: '{ "a": [0,1], "b": [0,2], "c": [{"0":1,"1":2},{"0":3,"1":4}] }'
@@ -197,7 +348,7 @@
     2
     4
 
-- name: object index in object value
+- name: object indexing in object value
   args:
     - '{ message: .[].message }'
   input: '[ {"message": "Hello, world" } ]'
@@ -206,14 +357,28 @@
       "message": "Hello, world"
     }
 
-- name: object index error
+- name: object indexing error
   args:
     - '.[.a + .b]'
   input: '{"a": 10, "b": 20}'
   error: |
     expected an array but got: object ({"a":10,"b":20})
 
-- name: object index syntax error
+- name: object indexing value error
+  args:
+    - '.["foo"]'
+  input: '[]'
+  error: |
+    expected an object but got: array ([])
+
+- name: object indexing key error
+  args:
+    - '.[null]'
+  input: '{}'
+  error: |
+    expected a string for object key but got: null
+
+- name: object indexing syntax error
   args:
     - '. a'
   input: '{}'
@@ -251,33 +416,33 @@
   error: |
     expected an object but got: number (128)
 
-- name: object index against null
+- name: object indexing against null
   args:
     - '.foo.bar.baz'
   input: 'null'
   expected: |
     null
 
-- name: object optional index
+- name: object optional indexing
   args:
     - '.foo?.bar?.baz?'
   input: '{"foo": 128}'
 
-- name: object optional index error
+- name: object optional indexing error
   args:
     - '.foo.bar.baz?'
   input: '{"foo": 128}'
   error: |
     expected an object but got: number (128)
 
-- name: object optional index after iterator error
+- name: object optional indexing after iterator error
   args:
     - '.[].foo?'
   input: '128'
   error: |
     cannot iterate over: number (128)
 
-- name: object optional index with optional operator
+- name: object optional indexing with optional operator
   args:
     - '.foo??, .'
   input: '0'
@@ -298,69 +463,78 @@
   error: |
     expected an object but got: number (1)
 
-- name: array index
+- name: array indexing
   args:
-    - '.[-5], .[-1], .[0], .[2], .[3], .[4], .[nan]'
-  input: '[16, 32, 48, 64]'
+    - '.[-4,-3,-2,-1,0,1,2,3,nan]'
+  input: '[0, 1, 2]'
   expected: |
     null
-    64
-    16
-    48
-    64
+    0
+    1
+    2
+    0
+    1
+    2
     null
     null
 
-- name: array slice
+- name: array slicing
   args:
     - -c
-    - '.[2:], .[:2], .[1:3], .[0:4], .[2:1], .[-2:], .[:-2], .[-2:-1], .[-10:], .[:10], .[10:], .[:-10]'
-  input: '[16, 32, 48, 64]'
+    - '[.[-4,-3,-2,-1,0,1,2,3:]], [.[:-4,-3,-2,-1,0,1,2,3]], [.[-1,0,1,2,3:-1,0,1,2,3]]'
+  input: '[0, 1, 2]'
   expected: |
-    [48,64]
-    [16,32]
-    [32,48]
-    [16,32,48,64]
+    [[0,1,2],[0,1,2],[1,2],[2],[0,1,2],[1,2],[2],[]]
+    [[],[],[0],[0,1],[],[0],[0,1],[0,1,2]]
+    [[],[],[],[],[2],[0,1],[],[0],[0,1],[0,1,2],[1],[],[],[1],[1,2],[],[],[],[],[2],[],[],[],[],[]]
+
+- name: array indexing and slicing by large number
+  args:
+    - -c
+    - '.[1e300,-1e300], .[-1e300,1e300:], .[:-1e300,1e300], .[-1e300:1e300], .[1e300:-1e300]'
+  input: '[0, 1, 2]'
+  expected: |
+    null
+    null
+    [0,1,2]
     []
-    [48,64]
-    [16,32]
-    [48]
-    [16,32,48,64]
-    [16,32,48,64]
     []
+    [0,1,2]
+    [0,1,2]
     []
 
-- name: array index and slice by large number
+- name: array indexing and slicing by large integer
   args:
     - -c
-    - '.[1e300], .[-1e300], .[-1e300:], .[1e300:], .[:-1e300], .[:1e300], .[-1e300:1e300], .[1e300:-1e300]'
-  input: '[16, 32, 48, 64]'
+    - '. as $x | 4722366482869645213696 as $y | $x[$y,-$y], $x[-$y,$y:], $x[:-$y,$y], $x[-$y:$y], $x[$y-$y], $x[$y/$y]'
+  input: '[0, 1, 2]'
   expected: |
     null
     null
-    [16,32,48,64]
-    []
+    [0,1,2]
     []
-    [16,32,48,64]
-    [16,32,48,64]
     []
+    [0,1,2]
+    [0,1,2]
+    0
+    1
 
-- name: array index and slice by infinite
+- name: array indexing and slicing by infinite
   args:
     - -c
-    - '.[infinite], .[-infinite], .[-infinite:], .[infinite:], .[:-infinite], .[:infinite], .[-infinite:infinite], .[infinite:-infinite]'
-  input: '[16, 32, 48, 64]'
+    - '.[infinite,-infinite], .[-infinite,infinite:], .[:-infinite,infinite], .[-infinite:infinite], .[infinite:-infinite]'
+  input: '[0, 1, 2]'
   expected: |
     null
     null
-    [16,32,48,64]
+    [0,1,2]
     []
     []
-    [16,32,48,64]
-    [16,32,48,64]
+    [0,1,2]
+    [0,1,2]
     []
 
-- name: array and string slice by object
+- name: array and string slicing by object
   args:
     - -c
     - '[.[{"start": (null,range(-3;4)), "end": (null,range(-3;4))}]]'
@@ -369,42 +543,28 @@
     [[0,1,2],[],[0],[0,1],[],[0],[0,1],[0,1,2],[0,1,2],[],[0],[0,1],[],[0],[0,1],[0,1,2],[1,2],[],[],[1],[],[],[1],[1,2],[2],[],[],[],[],[],[],[2],[0,1,2],[],[0],[0,1],[],[0],[0,1],[0,1,2],[1,2],[],[],[1],[],[],[1],[1,2],[2],[],[],[],[],[],[],[2],[],[],[],[],[],[],[],[]]
     ["abcde","ab","abc","abcd","","a","ab","abc","cde","","c","cd","","","","c","de","","","d","","","","","e","","","","","","","","abcde","ab","abc","abcd","","a","ab","abc","bcde","b","bc","bcd","","","b","bc","cde","","c","cd","","","","c","de","","","d","","","",""]
 
-- name: array slice by object against null
+- name: array slicing by object against null
   args:
     - '.[{"start": 1, "end": 2}]'
   input: 'null'
   expected: |
     null
 
-- name: array slice by object error
+- name: array slicing by object error
   args:
     - '.[{"start": 1}]'
   input: '[]'
   error: |
     expected "start" and "end" for slicing but got: object ({"start":1})
 
-- name: array slice against string error
+- name: array slicing against string error
   args:
     - '""[:{}]'
   input: '0'
   error: |
     expected a number for indexing an array but got: object ({})
 
-- name: array index and slice by large integer
-  args:
-    - -c
-    - '. as $x | 4722366482869645213696 as $y | $x[-$y], $x[$y], $x[-$y:], $x[:$y], $x[-$y:$y], $x[$y-$y], $x[$y/$y]'
-  input: '[16, 32, 48, 64]'
-  expected: |
-    null
-    null
-    [16,32,48,64]
-    [16,32,48,64]
-    [16,32,48,64]
-    16
-    32
-
-- name: array nested index by iterator
+- name: array nested indexing by iterator
   args:
     - -c
     - '[.[.[]],.[.[]:],.[:.[]],.[.[]:.[]],.[-.[]],.[--.[]]]'
@@ -412,7 +572,7 @@
   expected: |
     [0,1,2,[0,1,2],[1,2],[2],[],[0],[0,1],[],[0],[0,1],[],[],[1],[],[],[],0,2,1,0,1,2]
 
-- name: array index by iterator
+- name: array indexing by iterator
   args:
     - '.c[][.a[] + .b[]]'
   input: '{ "a": [0,1], "b": [0,2], "c": [[1,2,3,4],[5,6,7,8]] }'
@@ -426,7 +586,7 @@
     4
     8
 
-- name: array slice by iterator
+- name: array slicing by iterator
   args:
     - -c
     - '.c[][.a[] : .b[]]'
@@ -448,21 +608,21 @@
   error: |
     expected an array but got: object ({"foo":128})
 
-- name: array index against null
+- name: array indexing against null
   args:
     - '.[0]'
   input: 'null'
   expected: |
     null
 
-- name: array slice against null
+- name: array slicing against null
   args:
     - '.[0:1]'
   input: 'null'
   expected: |
     null
 
-- name: array index by array
+- name: array indexing by array
   args:
     - -c
     - '.[[1],[5,7,9],[],5,[3]]'
@@ -474,27 +634,34 @@
     8
     [1,9]
 
-- name: array index error
+- name: array indexing not number error
   args:
-    - '.["foo"]'
+    - '.[true]'
   input: '[]'
   error: |
-    expected an object but got: array ([])
+    expected a number for indexing an array but got: boolean (true)
 
-- name: array slice error
+- name: array slicing start error
+  args:
+    - '.["":]'
+  input: '[]'
+  error: |
+    expected a number for indexing an array but got: string ("")
+
+- name: array slicing end error
   args:
     - '.[:{}]'
   input: '[]'
   error: |
     expected a number for indexing an array but got: object ({})
 
-- name: string index and slice
+- name: string indexing and slicing
   args:
     - -c
     - '[.[-5],.[-1],.[0],.[3],.[4],.[6],.[2:4],.[-4:-2]]'
   input: '"12345"'
   expected: |
-    ["1","5","1","4","5","","34","23"]
+    ["1","5","1","4","5",null,"34","23"]
 
 - name: array construction
   args:
@@ -544,7 +711,7 @@
     - '.[]?'
   input: '0'
 
-- name: iterator with optional operator after index error
+- name: iterator with optional operator after indexing error
   args:
     - '.x[]?'
   input: '0'
@@ -577,7 +744,7 @@
   expected: |
     128
 
-- name: object optional index after iterator
+- name: object optional indexing after iterator
   args:
     - '[.[].name?]'
   input: '[ 1, { "name": 2 }, 3, { "name": 4 } ]'
@@ -1134,9 +1301,17 @@
   args:
     - -c
     - 'from_entries'
-  input: '[{"key":"a", "value":1}, {"Key":"b", "Value":2}, {"name":"c", "value":3}, {"Name":"d", "Value":4}]'
+  input: '[{"key":"a","Key":"b","value":1},{"Key":"b","Value":2},{"key":null,"name":"c","Name":"d","value":3},{"name":false,"Name":"d","value":null,"Value":4},{"key":"e"}]'
   expected: |
-    {"a":1,"b":2,"c":3,"d":4}
+    {"a":1,"b":2,"c":3,"d":null,"e":null}
+
+- name: from_entries function missing key
+  args:
+    - -c
+    - 'from_entries'
+  input: '[{"value":1}]'
+  error: |
+    expected a string for object key but got: null
 
 - name: with_entries function
   args:
@@ -1171,6 +1346,19 @@
     "abc"
     [1,2,3,4]
 
+- name: add function with a variable
+  args:
+    - '. as $x | [$x, {y:1}] | add, $x'
+  input: '{"x":0}'
+  expected: |
+    {
+      "x": 0,
+      "y": 1
+    }
+    {
+      "x": 0
+    }
+
 - name: add function error
   args:
     - 'add'
@@ -1193,10 +1381,20 @@
     [0,1,2,1,3,2]
     [1,2,3]
 
+- name: flatten/0 function error
+  args:
+    - 'flatten, flatten("")'
+  input: '0 [[]]'
+  expected: |
+    []
+  error: |
+    flatten cannot be applied to: number (0)
+    flatten cannot be applied to: string ("")
+
 - name: flatten/1 function
   args:
     - -c
-    - 'flatten(2)'
+    - 'flatten(0, 1.5, 2)'
   input: |
     []
     [0, [[[[[1]]]]]]
@@ -1204,10 +1402,25 @@
     {"x": [1], "y": [[2]], "z": [[[3]]]}
   expected: |
     []
+    []
+    []
+    [0,[[[[[1]]]]]]
+    [0,1]
     [0,[[[1]]]]
+    [0,[1,[2]],[1,[[3],2]]]
+    [0,1,2,1,3,2]
     [0,1,2,1,[3],2]
+    [[1],[[2]],[[[3]]]]
+    [1,2,3]
     [1,2,[3]]
 
+- name: flatten/1 function depth error
+  args:
+    - 'flatten(-1)'
+  input: '[]'
+  error: |
+    flatten depth must not be negative: number (-1)
+
 - name: min, min_by, max, max_by functions
   args:
     - -c
@@ -1246,6 +1459,16 @@
     ["apple","banana","cat","dog","hello","world"]
     ["cat","hello","banana"]
 
+- name: min, max, sort, unique functions error
+  args:
+    - 'try min catch ., try max catch ., try sort catch ., try unique catch .'
+  input: '0'
+  expected: |
+    "min cannot be applied to: number (0)"
+    "max cannot be applied to: number (0)"
+    "sort cannot be applied to: number (0)"
+    "unique cannot be applied to: number (0)"
+
 - name: arrays, objects, iterables, booleans, numbers, strings, nulls, values, scalars functions
   args:
     - -c
@@ -1529,7 +1752,7 @@
 - name: contains function
   args:
     - -c
-    - '.[] as $x | (null,false,true,[],[3,4],[3,1],"foo","ll",{},{"a":1},{"b":[5]}) as $y | $x | [$x,$y,contains($y)]?'
+    - '.[] as $x | (null,false,true,[],[3,4],[3,1],"foo","ll",{},{"a":1},{"a":""},{"b":[5]},{"a":3,"b":[5]}) as $y | $x | [$x,$y,contains($y)]?'
   input: '[null,false,true,[],[1,2,3],"","hello",{"a":3,"b":[4,5,6]}]'
   expected: |
     [null,null,true]
@@ -1547,7 +1770,9 @@
     ["hello","ll",true]
     [{"a":3,"b":[4,5,6]},{},true]
     [{"a":3,"b":[4,5,6]},{"a":1},false]
+    [{"a":3,"b":[4,5,6]},{"a":""},false]
     [{"a":3,"b":[4,5,6]},{"b":[5]},true]
+    [{"a":3,"b":[4,5,6]},{"a":3,"b":[5]},true]
 
 - name: contains function against unicode strings
   args:
@@ -1777,17 +2002,21 @@
   args:
     - -c
     - '[combinations]'
-  input: '[[1, 2, 3], [4, 5, 6]]'
+  input: '[] [[0]] [[1, 2, 3], [4, 5, 6]]'
   expected: |
+    [[]]
+    [[0]]
     [[1,4],[1,5],[1,6],[2,4],[2,5],[2,6],[3,4],[3,5],[3,6]]
 
 - name: combinations/1 function
   args:
     - -c
     - '[combinations(3)]'
-  input: '[0, 1]'
+  input: '[] [0] [1, 2]'
   expected: |
-    [[0,0,0],[0,0,1],[0,1,0],[0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]]
+    []
+    [[0,0,0]]
+    [[1,1,1],[1,1,2],[1,2,1],[1,2,2],[2,1,1],[2,1,2],[2,2,1],[2,2,2]]
 
 - name: join function
   args:
@@ -1833,11 +2062,11 @@
     - '.[] | try join(",") catch .'
   input: '[null, false, true, 1, "a"]'
   expected: |
-    "cannot iterate over: null"
-    "cannot iterate over: boolean (false)"
-    "cannot iterate over: boolean (true)"
-    "cannot iterate over: number (1)"
-    "cannot iterate over: string (\"a\")"
+    "join cannot be applied to: null"
+    "join cannot be applied to: boolean (false)"
+    "join cannot be applied to: boolean (true)"
+    "join cannot be applied to: number (1)"
+    "join cannot be applied to: string (\"a\")"
 
 - name: join function non-string separator
   args:
@@ -2046,6 +2275,23 @@
     2
     3
 
+- name: function declaration with builtin function name conflict
+  args:
+    - 'def empty: . % 2; range(5) | select(empty > 0)'
+  input: 'null'
+  expected: |
+    1
+    3
+
+- name: function declaration with builtin function name conflict
+  args:
+    - 'def select(f): f; null, 0 | numbers, select(.)'
+  input: 'null'
+  expected: |
+    null
+    0
+    0
+
 - name: function declaration with argument name conflict
   args:
     - 'def update: .[1:]; [range(3)] | while(length>0; update)'
@@ -2142,13 +2388,13 @@
   args:
     - -c
     - '[.[] + .[]], [.[] - .[]], [.[] * .[]], [.[] / .[]], [.[]  % .[]]'
-  input: '[-1, 47, 4722366482869645213696, 557702036893939360447070208]'
+  input: '[-1, 47, 9223372036854775807, 557702036893939360447070208]'
   expected: |
-    [-2,46,4722366482869645213695,557702036893939360447070207,46,94,4722366482869645213743,557702036893939360447070255,4722366482869645213695,4722366482869645213743,9444732965739290427392,557706759260422230092283904,557702036893939360447070207,557702036893939360447070255,557706759260422230092283904,1115404073787878720894140416]
-    [0,48,4722366482869645213697,557702036893939360447070209,-48,0,4722366482869645213649,557702036893939360447070161,-4722366482869645213697,-4722366482869645213649,0,557697314527456490801856512,-557702036893939360447070209,-557702036893939360447070161,-557697314527456490801856512,0]
-    [1,-47,-4722366482869645213696,-557702036893939360447070208,-47,2209,221951224694873325043712,26211995734015149941012299776,-4722366482869645213696,221951224694873325043712,22300745198530623141535718272648361505980416,2633673406456069531769085256563226197133275168768,-557702036893939360447070208,26211995734015149941012299776,2633673406456069531769085256563226197133275168768,311031561955648899562865430629603887429045530881163264]
-    [1,-47,-4722366482869645213696,-557702036893939360447070208,-0.02127659574468085,1,100475882614247770000,1.1866000784977433e+25,-2.117582368135751e-22,9.952637130238029e-21,1,118098,-1.7930721672981344e-27,8.427439186301232e-26,0.000008467543904215143,1]
-    [0,0,0,0,-1,0,8,37,-1,47,0,0,-1,47,4722366482869645213696,0]
+    [-2,46,9223372036854775806,557702036893939360447070207,46,94,9223372036854775854,557702036893939360447070255,9223372036854775806,9223372036854775854,18446744073709551614,557702046117311397301846015,557702036893939360447070207,557702036893939360447070255,557702046117311397301846015,1115404073787878720894140416]
+    [0,48,9223372036854775808,557702036893939360447070209,-48,0,9223372036854775760,557702036893939360447070161,-9223372036854775808,-9223372036854775760,0,557702027670567323592294401,-557702036893939360447070209,-557702036893939360447070161,-557702027670567323592294401,0]
+    [1,-47,-9223372036854775807,-557702036893939360447070208,-47,2209,433498485732174462929,26211995734015149941012299776,-9223372036854775807,433498485732174462929,85070591730234615847396907784232501249,5143893371984510803678792604831111805828857856,-557702036893939360447070208,26211995734015149941012299776,5143893371984510803678792604831111805828857856,311031561955648899562865430629603887429045530881163264]
+    [1,-47,-9223372036854775807,-557702036893939360447070208,-0.02127659574468085,1,196241958230952670,1.1866000784977433e+25,-1.0842021724855044e-19,5.095750210681871e-18,1,60466176,-1.7930721672981344e-27,8.427439186301232e-26,1.65381716879202e-8,1]
+    [0,0,0,0,-1,0,35,37,-1,47,0,60466176,-1,47,9223372036854775807,0]
 
 - name: add, subtract, multiply, divide, modulo operators precedence
   args:
@@ -2333,7 +2579,7 @@
 
 - name: multiply strings
   args:
-    - '[-1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 3.7, 10, 9444732965739290427392 / 4722366482869645213696, 1000000000, infinite, -infinite, nan, -1e300, 1e300][] * "abc"'
+    - '[-1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 3.7, 10, 9444732965739290427392 / 4722366482869645213696, 100000000, infinite, -infinite, nan, -1e300, 1e300][] * "abc"'
   input: 'null'
   expected: |
     null
@@ -2544,7 +2790,7 @@
     "111111101111111110000000010000000010000000010000000010000000010000000010000000010111111110111111110111111110111111110111"
     "111110111111110111111110"
 
-- name: comparison operators does not associate
+- name: comparison operators associativity error
   args:
     - '. == . == .'
   input: '1'
@@ -2657,22 +2903,39 @@
 
 - name: condition
   args:
-    - '.[] | if . then . else empty end'
-  input: '[false, true, 0, 1]'
+    - 'if . then . else [.] end'
+  input: 'null false true 0'
   expected: |
+    [
+      null
+    ]
+    [
+      false
+    ]
     true
     0
-    1
 
-- name: condition with elif
+- name: condition with elif clause
   args:
-    - '.[] | if . then . elif [] then . else empty end'
-  input: '[false, true, 0, 1]'
+    - 'if . == null then . elif not then [.] elif . == true then [[.]] else [[[.]]] end'
+  input: 'null false true 0'
   expected: |
-    false
-    true
-    0
-    1
+    null
+    [
+      false
+    ]
+    [
+      [
+        true
+      ]
+    ]
+    [
+      [
+        [
+          0
+        ]
+      ]
+    ]
 
 - name: condition without else clause
   args:
@@ -2805,7 +3068,7 @@
     error: 0
   exit_code: 5
 
-- name: try and index precedence
+- name: try and indexing precedence
   args:
     - 'try 0 .[error(0)]'
   input: 'null'
@@ -3521,10 +3784,10 @@
 - name: first/1, last/1, nth functions
   args:
     - -c
-    - '[first(.[]), last(.[]), nth(0), nth(3), nth(0;.[]), nth(3;.[]), nth(5;.[])]'
+    - '[first(.[]), last(.[]), nth(0,3,5), nth(0,3,5;.[]), nth(9; range(infinite))]'
   input: '[1,2,3,4,5]'
   expected: |
-    [1,5,1,4,1,4]
+    [1,5,1,4,null,1,4,9]
 
 - name: first/1 function with optional operator
   args:
@@ -4008,6 +4271,14 @@
   expected: |
     10
 
+- name: setpath function error
+  args:
+    - -c
+    - 'setpath([-1]; 10)'
+  input: '[]'
+  error: |
+    setpath cannot be applied to: number (-1)
+
 - name: setpath function error
   args:
     - -c
@@ -4158,7 +4429,7 @@
     {"bar":[1]}
     {"bar":[0],"foo":[0,1,4]}
 
-- name: del function with slice
+- name: del function with array slicing
   args:
     - -c
     - 'del(.[1], .[-6], .[2], .[-3:9])'
@@ -4182,7 +4453,7 @@
   expected: |
     [3,1,3]
 
-- name: assignment operator against array with slice
+- name: assignment operator against array with slicing
   args:
     - -c
     - '.[2:4] = ([], [0], [4,3,2]), .[1:-1] = [3,2], .[2:0] = [.[]], .[10:] = [1],
@@ -4205,7 +4476,7 @@
     [1,9,5]
     [9]
 
-- name: assignment operator deeply
+- name: assignment operator with object and array indexing
   args:
     - -c
     - '.foo.[0].bar.[1] = 1'
@@ -4213,7 +4484,7 @@
   expected: |
     {"foo":[{"bar":[null,1]}]}
 
-- name: assignment operator deeply
+- name: assignment operator against array with suffix array indexing
   args:
     - -c
     - '.[2][2] = 1'
@@ -4221,7 +4492,15 @@
   expected: |
     [1,null,[null,null,1]]
 
-- name: assignment operator deeply
+- name: assignment operator against array with suffix object indexing
+  args:
+    - -c
+    - '.[2].foo = 1'
+  input: '[1]'
+  expected: |
+    [1,null,{"foo":1}]
+
+- name: assignment operator against object with multiple suffix indexing
   args:
     - -c
     - '.foo[2].bar = 2'
@@ -4229,6 +4508,22 @@
   expected: |
     {"bar":3,"foo":[1,null,{"bar":2}]}
 
+- name: assignment operator with query and suffix object indexing
+  args:
+    - -c
+    - '(.foo).bar = 1'
+  input: 'null'
+  expected: |
+    {"foo":{"bar":1}}
+
+- name: assignment operator with object indexing and iterator suffix
+  args:
+    - -c
+    - '.foo[].bar = 1'
+  input: '{"foo":[null,null]}'
+  expected: |
+    {"foo":[{"bar":1},{"bar":1}]}
+
 - name: assignment operator query
   args:
     - -c
@@ -4239,10 +4534,10 @@
 
 - name: assignment operator array index limit error
   args:
-    - '.[100000000] = 1'
+    - '.[200000000] = 1'
   input: '[]'
   error: |
-    array index too large: 100000000
+    array index too large: 200000000
 
 - name: assignment operator with error function
   args:
@@ -4372,7 +4667,7 @@
     {"foo":1}
     {"foo":2}
 
-- name: update operators does not associate
+- name: update operators associativity error
   args:
     - '. += 1 -= 2'
   input: '1'
@@ -4508,18 +4803,62 @@
 - name: path function nested
   args:
     - -c
-    - 'path(.a[path(.b)[0]])'
+    - 'path(.a[path(.b[.a:.b])[0]])'
   input: '{"a":{"b":0}}'
   expected: |
     ["a","b"]
 
-- name: path function error
+- name: path function error with arithmetic operator
   args:
     - 'path(. + 1)'
-  input: '0'
+  input: 'null'
   error: |
     invalid path against: number (1)
 
+- name: path function error with object indexing
+  args:
+    - 'path({}.x)'
+  input: '{}'
+  error: |
+    invalid path against: object ({})
+
+- name: path function error with array indexing
+  args:
+    - 'path([0][0 + 0])'
+  input: '[0]'
+  error: |
+    invalid path against: array ([0])
+
+- name: path function error with array slicing
+  args:
+    - 'path([0][0:1])'
+  input: '[0]'
+  error: |
+    invalid path against: array ([0])
+
+- name: path function error with getpath function
+  args:
+    - 'path({} | getpath([]))'
+  input: '{}'
+  error: |
+    invalid path against: object ({})
+
+- name: path function with binding array slicing
+  args:
+    - '.[:1] as $x | path($x.[0])'
+  input: '[0]'
+  expected: |
+    [
+      0
+    ]
+
+- name: path function error with binding array slicing
+  args:
+    - '.[:0] as $x | path($x.[0])'
+  input: '[0]'
+  error: |
+    invalid path against: array ([])
+
 - name: path function with error function
   args:
     - '[path(error)]'
@@ -4542,12 +4881,19 @@
   error: |
     error: x
 
-- name: path function iterate error
+- name: path function iterate error of array
   args:
-    - 'try ((map(select(.a == 0))[].b) = 10) catch .'
-  input: '[{"a":0},{"a":1}]'
-  expected: |
-    "invalid path on iterating against: array ([{\"a\":0}])"
+    - '[.[]][].a = 1'
+  input: '[{"a":0}]'
+  error: |
+    invalid path on iterating against: array ([{"a":0}])
+
+- name: path function iterate error of object
+  args:
+    - '{}[] = 10'
+  input: '{}'
+  error: |
+    invalid path on iterating against: object ({})
 
 - name: paths/0 function
   args:
@@ -4620,13 +4966,13 @@
     "2017-07-14T02:40:00-0700"
     "2017-07-13T19:40:00-0700"
     "2017-07-14T02:40:00Z"
-    1567890123
+    1567890123.456
     "2019-09-07T21:02:03Z"
     "2019-09-07T21:02:03Z"
     "2019-09-07T21:02:03-0700"
     "2019-09-07T14:02:03-0700"
     "2019-09-07T21:02:03Z"
-    1600000000
+    1600000000.111
     "2020-09-13T12:26:40Z"
     "2020-09-13T12:26:40Z"
     "2020-09-13T12:26:40-0700"
@@ -5286,8 +5632,8 @@
     "bbcABC☆★☆ABCbbc"
     "bABC☆★☆ABCb"
     "bbcABC☆★☆ABCbbc"
-    "bbcABC☆★☆ABCcbc"
     "cbcABC☆★☆ABCbbc"
+    "bbcABC☆★☆ABCcbc"
     "cbcABC☆★☆ABCcbc"
     "bcbcBCBC☆★☆BCBCbcbc"
     "abcABC☆★☆★☆ABCabc"
@@ -5518,8 +5864,8 @@
 
 - name: destructuring alternative operator
   args:
-    - '.[] | . as {a:$a} ?// [$a] ?// $a | $a'
-  input: '[[1],[2],{"a":3},4]'
+    - '. as {$a} ?// [$a] ?// $a | $a'
+  input: '[1] [2] {"a":3} 4'
   expected: |
     1
     2
@@ -5529,8 +5875,8 @@
 - name: destructuring alternative operator with error backtrack
   args:
     - -c
-    - '.[] | . as {a:$a} ?// [$a] ?// $a | if 1 < $a and $a < 4 then $a|error else $a end'
-  input: '[[1],[2],{"a":3},4]'
+    - '. as {$a} ?// [$a] ?// $a | if 1 < $a and $a < 4 then $a|error else $a end'
+  input: '[1] [2] {"a":3} 4'
   expected: |
     1
     [2]
@@ -5540,8 +5886,8 @@
 - name: destructuring alternative operator with multiple variables
   args:
     - -c
-    - '.[] | . as {$a, b: [$c, {$d}]} ?// [$a, {$b}, $e] ?// $f | [$a, $b, $c, $d, $e, $f]'
-  input: '[{"a":1,"b":[2,{"d":3}]},[4,{"b":5,"c":6},7,8,9],"foo"]'
+    - '. as {$a, b: [$c, {$d}]} ?// [$a, {$b}, $e] ?// $f | [$a, $b, $c, $d, $e, $f]'
+  input: '{"a":1,"b":[2,{"d":3}]} [4,{"b":5,"c":6},7,8,9] "foo"'
   expected: |
     [1,null,2,3,null,null]
     [4,5,null,null,7,null]
@@ -6113,6 +6459,13 @@
     [["z",0]]
     [["z"]]
 
+- name: stream option with empty input
+  args:
+    - --stream
+    - '.'
+  input: ''
+  expected: ''
+
 - name: stream option with null input option
   args:
     - -n
@@ -6151,6 +6504,19 @@
     [["c"],3]
     [["c"]]
 
+- name: stream option with unterminated input
+  args:
+    - -c
+    - --stream
+    - '.'
+  input: '{"a":1,'
+  expected: |
+    [["a"],1]
+  error: |
+    invalid json: <stdin>
+        {"a":1,
+               ^  unexpected EOF
+
 - name: yaml input option
   args:
     - --yaml-input
@@ -6525,6 +6891,16 @@
            ^  unexpected token "☆"
   exit_code: 3
 
+- name: invalid query
+  args:
+    - "\\/"
+  input: '{}'
+  error: |
+    invalid query: \/
+        \/
+        ^  unexpected token "\\"
+  exit_code: 3
+
 - name: invalid query
   args:
     - "{\n[]}"
@@ -6602,20 +6978,29 @@
     expected argument for flag `-f'
   exit_code: 2
 
-- name: invalid json eof
+- name: invalid json unexpected eof error
   input: '{'
   error: |
     invalid json: <stdin>
         {
          ^  unexpected EOF
 
-- name: invalid json eof with multibyte characters
+- name: invalid json unexpected eof error with multibyte characters
   input: '{ "12345":'
   error: |
     invalid json: <stdin>
         { "12345":
                        ^  unexpected EOF
 
+- name: invalid json unexpected eof error with multiple lines
+  input: |
+    [0
+    ,[
+  error: |
+    invalid json: <stdin>:2
+        2 | ,[
+              ^  unexpected EOF
+
 - name: invalid json invalid character with multibyte characters
   input: |
     {
@@ -6695,7 +7080,7 @@
     - 'testdata/8.json'
   error: |
     invalid json: testdata/8.json
-        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ,, 1, 1, 1, 1, 1, 1, 1
+        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1
                                                    ^  invalid character ',' looking for beginning of value
 
 - name: json file error json
@@ -6704,8 +7089,8 @@
     - 'testdata/9.json'
   error: |
     invalid json: testdata/9.json:3
-        3 | ", "0", "0", "0", "0", , "0", "0"]
-                                       ^  invalid character ',' looking for beginning of value
+        3 | 0", "0", "0", "0", "0", "0", "0", , "0", "0"]
+                                                     ^  invalid character ',' looking for beginning of value
 
 - name: json file error json with multibyte character in the error line
   args:
diff --git a/cli/testdata/8.json b/cli/testdata/8.json
index 63050f2..09128eb 100644
--- a/cli/testdata/8.json
+++ b/cli/testdata/8.json
@@ -1 +1 @@
-[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ,, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
diff --git a/code.go b/code.go
index f1935d8..715178e 100644
--- a/code.go
+++ b/code.go
@@ -25,13 +25,14 @@ const (
 	opbacktrack
 	opjump
 	opjumpifnot
+	opindex
 	opcall
 	opcallrec
 	oppushpc
 	opcallpc
 	opscope
 	opret
-	opeach
+	opiter
 	opexpbegin
 	opexpend
 	oppathbegin
@@ -74,6 +75,8 @@ func (op opcode) String() string {
 		return "jump"
 	case opjumpifnot:
 		return "jumpifnot"
+	case opindex:
+		return "index"
 	case opcall:
 		return "call"
 	case opcallrec:
@@ -86,8 +89,8 @@ func (op opcode) String() string {
 		return "scope"
 	case opret:
 		return "ret"
-	case opeach:
-		return "each"
+	case opiter:
+		return "iter"
 	case opexpbegin:
 		return "expbegin"
 	case opexpend:
diff --git a/compare.go b/compare.go
index 9f0d533..939c7d9 100644
--- a/compare.go
+++ b/compare.go
@@ -7,16 +7,7 @@ import (
 
 func compare(l, r interface{}) int {
 	return binopTypeSwitch(l, r,
-		func(l, r int) interface{} {
-			switch {
-			case l < r:
-				return -1
-			case l == r:
-				return 0
-			default:
-				return 1
-			}
-		},
+		compareInt,
 		func(l, r float64) interface{} {
 			switch {
 			case l < r || math.IsNaN(l):
@@ -41,20 +32,16 @@ func compare(l, r interface{}) int {
 			}
 		},
 		func(l, r []interface{}) interface{} {
-			for i := 0; ; i++ {
-				if i >= len(l) {
-					if i >= len(r) {
-						return 0
-					}
-					return -1
-				}
-				if i >= len(r) {
-					return 1
-				}
+			n := len(l)
+			if len(r) < n {
+				n = len(r)
+			}
+			for i := 0; i < n; i++ {
 				if cmp := compare(l[i], r[i]); cmp != 0 {
 					return cmp
 				}
 			}
+			return compareInt(len(l), len(r))
 		},
 		func(l, r map[string]interface{}) interface{} {
 			lk, rk := funcKeys(l), funcKeys(r)
@@ -69,28 +56,31 @@ func compare(l, r interface{}) int {
 			return 0
 		},
 		func(l, r interface{}) interface{} {
-			ln, rn := getTypeOrdNum(l), getTypeOrdNum(r)
-			switch {
-			case ln < rn:
-				return -1
-			case ln == rn:
-				return 0
-			default:
-				return 1
-			}
+			return compareInt(typeIndex(l), typeIndex(r))
 		},
 	).(int)
 }
 
-func getTypeOrdNum(v interface{}) int {
+func compareInt(l, r int) interface{} {
+	switch {
+	case l < r:
+		return -1
+	case l == r:
+		return 0
+	default:
+		return 1
+	}
+}
+
+func typeIndex(v interface{}) int {
 	switch v := v.(type) {
-	case nil:
+	default:
 		return 0
 	case bool:
-		if v {
-			return 2
+		if !v {
+			return 1
 		}
-		return 1
+		return 2
 	case int, float64, *big.Int:
 		return 3
 	case string:
@@ -99,7 +89,5 @@ func getTypeOrdNum(v interface{}) int {
 		return 5
 	case map[string]interface{}:
 		return 6
-	default:
-		return -1
 	}
 }
diff --git a/compiler.go b/compiler.go
index 00daa04..3a57655 100644
--- a/compiler.go
+++ b/compiler.go
@@ -2,7 +2,6 @@ package gojq
 
 import (
 	"context"
-	"encoding/json"
 	"errors"
 	"fmt"
 	"sort"
@@ -18,6 +17,7 @@ type compiler struct {
 	inputIter     Iter
 	codes         []*code
 	codeinfos     []codeinfo
+	builtinScope  *scopeinfo
 	scopes        []*scopeinfo
 	scopecnt      int
 }
@@ -87,6 +87,7 @@ func Compile(q *Query, options ...CompilerOption) (*Code, error) {
 	for _, opt := range options {
 		opt(c)
 	}
+	c.builtinScope = c.newScope()
 	scope := c.newScope()
 	c.scopes = []*scopeinfo{scope}
 	setscope := c.lazy(func() *code {
@@ -190,8 +191,11 @@ func (c *compiler) compileImport(i *Import) error {
 		}
 	}
 	c.appendCodeInfo("module " + path)
-	defer c.appendCodeInfo("end of module " + path)
-	return c.compileModule(q, alias)
+	if err = c.compileModule(q, alias); err != nil {
+		return err
+	}
+	c.appendCodeInfo("end of module " + path)
+	return nil
 }
 
 func (c *compiler) compileModule(q *Query, alias string) error {
@@ -274,6 +278,16 @@ func (c *compiler) lookupFuncOrVariable(name string) (*funcinfo, *varinfo) {
 	return nil, nil
 }
 
+func (c *compiler) lookupBuiltin(name string, argcnt int) *funcinfo {
+	s := c.builtinScope
+	for i := len(s.funcs) - 1; i >= 0; i-- {
+		if f := s.funcs[i]; f.name == name && f.argcnt == argcnt {
+			return f
+		}
+	}
+	return nil
+}
+
 func (c *compiler) newScope() *scopeinfo {
 	i := c.scopecnt // do not use len(c.scopes) because it pops
 	c.scopecnt++
@@ -294,29 +308,22 @@ func (c *compiler) newScopeDepth() func() {
 func (c *compiler) compileFuncDef(e *FuncDef, builtin bool) error {
 	var scope *scopeinfo
 	if builtin {
-		scope = c.scopes[0]
-		for i := len(scope.funcs) - 1; i >= 0; i-- {
-			if f := scope.funcs[i]; f.name == e.Name && f.argcnt == len(e.Args) {
-				return nil
-			}
-		}
+		scope = c.builtinScope
 	} else {
 		scope = c.scopes[len(c.scopes)-1]
 	}
 	defer c.lazy(func() *code {
-		return &code{op: opjump, v: c.pc()}
+		return &code{op: opjump, v: len(c.codes)}
 	})()
 	c.appendCodeInfo(e.Name)
-	defer c.appendCodeInfo("end of " + e.Name)
-	pc := c.pc()
-	scope.funcs = append(scope.funcs, &funcinfo{e.Name, pc, len(e.Args)})
+	scope.funcs = append(scope.funcs, &funcinfo{e.Name, len(c.codes), len(e.Args)})
 	defer func(scopes []*scopeinfo, variables []string) {
 		c.scopes, c.variables = scopes, variables
 	}(c.scopes, c.variables)
 	c.variables = c.variables[len(c.variables):]
 	scope = c.newScope()
 	if builtin {
-		c.scopes = []*scopeinfo{c.scopes[0], scope}
+		c.scopes = []*scopeinfo{c.builtinScope, scope}
 	} else {
 		c.scopes = append(c.scopes, scope)
 	}
@@ -351,7 +358,11 @@ func (c *compiler) compileFuncDef(e *FuncDef, builtin bool) error {
 		}
 		c.append(&code{op: opload, v: v})
 	}
-	return c.compile(e.Body)
+	if err := c.compile(e.Body); err != nil {
+		return err
+	}
+	c.appendCodeInfo("end of " + e.Name)
+	return nil
 }
 
 func (c *compiler) compileQuery(e *Query) error {
@@ -425,15 +436,15 @@ func (c *compiler) compileQuery(e *Query) error {
 
 func (c *compiler) compileComma(l, r *Query) error {
 	setfork := c.lazy(func() *code {
-		return &code{op: opfork, v: c.pc() + 1}
+		return &code{op: opfork, v: len(c.codes)}
 	})
 	if err := c.compileQuery(l); err != nil {
 		return err
 	}
-	setfork()
 	defer c.lazy(func() *code {
-		return &code{op: opjump, v: c.pc()}
+		return &code{op: opjump, v: len(c.codes)}
 	})()
+	setfork()
 	return c.compileQuery(r)
 }
 
@@ -442,23 +453,23 @@ func (c *compiler) compileAlt(l, r *Query) error {
 	found := c.newVariable()
 	c.append(&code{op: opstore, v: found})
 	setfork := c.lazy(func() *code {
-		return &code{op: opfork, v: c.pc()} // opload found
+		return &code{op: opfork, v: len(c.codes)} // opload found
 	})
 	if err := c.compileQuery(l); err != nil {
 		return err
 	}
 	c.append(&code{op: opdup})
-	c.append(&code{op: opjumpifnot, v: c.pc() + 4}) // oppop
-	c.append(&code{op: oppush, v: true})            // found some value
+	c.append(&code{op: opjumpifnot, v: len(c.codes) + 4}) // oppop
+	c.append(&code{op: oppush, v: true})                  // found some value
 	c.append(&code{op: opstore, v: found})
 	defer c.lazy(func() *code {
-		return &code{op: opjump, v: c.pc()} // ret
+		return &code{op: opjump, v: len(c.codes)}
 	})()
 	c.append(&code{op: oppop})
 	c.append(&code{op: opbacktrack})
 	setfork()
 	c.append(&code{op: opload, v: found})
-	c.append(&code{op: opjumpifnot, v: c.pc() + 3})
+	c.append(&code{op: opjumpifnot, v: len(c.codes) + 3})
 	c.append(&code{op: opbacktrack}) // if found, backtrack
 	c.append(&code{op: oppop})
 	return c.compileQuery(r)
@@ -467,8 +478,9 @@ func (c *compiler) compileAlt(l, r *Query) error {
 func (c *compiler) compileQueryUpdate(l, r *Query, op Operator) error {
 	switch op {
 	case OpAssign:
-		// .foo.bar = f => setpath(["foo", "bar"]; f)
-		if xs := l.toIndices(); xs != nil {
+		// optimize assignment operator with object and array indexing
+		//   .foo.[0] = f => setpath(["foo",0]; f)
+		if xs := l.toIndices(nil); xs != nil {
 			// ref: compileCall
 			v := c.newVariable()
 			c.append(&code{op: opstore, v: v})
@@ -517,7 +529,12 @@ func (c *compiler) compileQueryUpdate(l, r *Query, op Operator) error {
 	}
 }
 
-func (c *compiler) compileBind(b *Bind) error {
+func (c *compiler) compileBind(e *Term, b *Bind) error {
+	c.append(&code{op: opdup})
+	c.append(&code{op: opexpbegin})
+	if err := c.compileTerm(e); err != nil {
+		return err
+	}
 	var pc int
 	var vs [][2]int
 	for i, p := range b.Patterns {
@@ -534,97 +551,86 @@ func (c *compiler) compileBind(b *Bind) error {
 				c.append(&code{op: opstore, v: v})
 			}
 		}
-		vs, err = c.compilePattern(p)
-		if err != nil {
+		if vs, err = c.compilePattern(vs[:0], p); err != nil {
 			return err
 		}
 		if i < len(b.Patterns)-1 {
 			defer c.lazy(func() *code {
 				return &code{op: opjump, v: pc}
 			})()
-			pcc = c.pc()
+			pcc = len(c.codes)
 		}
 	}
 	if len(b.Patterns) > 1 {
-		pc = c.pc()
+		pc = len(c.codes)
 	}
 	if len(b.Patterns) == 1 && c.codes[len(c.codes)-2].op == opexpbegin {
 		c.codes[len(c.codes)-2].op = opnop
 	} else {
-		c.append(&code{op: opexpend}) // ref: compileTermSuffix
+		c.append(&code{op: opexpend})
 	}
 	return c.compileQuery(b.Body)
 }
 
-func (c *compiler) compilePattern(p *Pattern) ([][2]int, error) {
+func (c *compiler) compilePattern(vs [][2]int, p *Pattern) ([][2]int, error) {
+	var err error
 	c.appendCodeInfo(p)
 	if p.Name != "" {
 		v := c.pushVariable(p.Name)
 		c.append(&code{op: opstore, v: v})
-		return [][2]int{v}, nil
+		return append(vs, v), nil
 	} else if len(p.Array) > 0 {
-		var vs [][2]int
 		v := c.newVariable()
 		c.append(&code{op: opstore, v: v})
 		for i, p := range p.Array {
-			c.append(&code{op: oppush, v: i})
-			c.append(&code{op: opload, v: v})
 			c.append(&code{op: opload, v: v})
-			// ref: compileCall
-			c.append(&code{op: opcall, v: [3]interface{}{internalFuncs["_index"].callback, 2, "_index"}})
-			ns, err := c.compilePattern(p)
-			if err != nil {
+			c.append(&code{op: opindex, v: i})
+			if vs, err = c.compilePattern(vs, p); err != nil {
 				return nil, err
 			}
-			vs = append(vs, ns...)
 		}
 		return vs, nil
 	} else if len(p.Object) > 0 {
-		var vs [][2]int
 		v := c.newVariable()
 		c.append(&code{op: opstore, v: v})
 		for _, kv := range p.Object {
 			var key, name string
-			if kv.KeyOnly != "" {
-				key, name = kv.KeyOnly[1:], kv.KeyOnly
-				c.append(&code{op: oppush, v: key})
-			} else if kv.Key != "" {
-				key = kv.Key
-				if key != "" && key[0] == '$' {
+			c.append(&code{op: opload, v: v})
+			if key = kv.Key; key != "" {
+				if key[0] == '$' {
 					key, name = key[1:], key
 				}
-				c.append(&code{op: oppush, v: key})
 			} else if kv.KeyString != nil {
-				c.append(&code{op: opload, v: v})
-				if err := c.compileString(kv.KeyString, nil); err != nil {
-					return nil, err
+				if key = kv.KeyString.Str; key == "" {
+					if err := c.compileString(kv.KeyString, nil); err != nil {
+						return nil, err
+					}
 				}
 			} else if kv.KeyQuery != nil {
-				c.append(&code{op: opload, v: v})
 				if err := c.compileQuery(kv.KeyQuery); err != nil {
 					return nil, err
 				}
 			}
-			c.append(&code{op: opload, v: v})
-			c.append(&code{op: opload, v: v})
-			// ref: compileCall
-			c.append(&code{op: opcall, v: [3]interface{}{internalFuncs["_index"].callback, 2, "_index"}})
+			if key != "" {
+				c.append(&code{op: opindex, v: key})
+			} else {
+				c.append(&code{op: opload, v: v})
+				c.append(&code{op: oppush, v: nil})
+				// ref: compileCall
+				c.append(&code{op: opcall, v: [3]interface{}{internalFuncs["_index"].callback, 2, "_index"}})
+			}
 			if name != "" {
 				if kv.Val != nil {
 					c.append(&code{op: opdup})
 				}
-				ns, err := c.compilePattern(&Pattern{Name: name})
-				if err != nil {
+				if vs, err = c.compilePattern(vs, &Pattern{Name: name}); err != nil {
 					return nil, err
 				}
-				vs = append(vs, ns...)
 			}
 			if kv.Val != nil {
-				ns, err := c.compilePattern(kv.Val)
-				if err != nil {
+				if vs, err = c.compilePattern(vs, kv.Val); err != nil {
 					return nil, err
 				}
-				vs = append(vs, ns...)
 			}
 		}
 		return vs, nil
@@ -650,17 +656,17 @@ func (c *compiler) compileIf(e *If) error {
 	}
 	pcc := len(c.codes)
 	setjumpifnot := c.lazy(func() *code {
-		return &code{op: opjumpifnot, v: c.pc() + 1} // if falsy, skip then clause
+		return &code{op: opjumpifnot, v: len(c.codes)} // skip then clause
 	})
 	f = c.newScopeDepth()
 	if err := c.compileQuery(e.Then); err != nil {
 		return err
 	}
 	f()
-	setjumpifnot()
 	defer c.lazy(func() *code {
-		return &code{op: opjump, v: c.pc()} // jump to ret after else clause
+		return &code{op: opjump, v: len(c.codes)}
 	})()
+	setjumpifnot()
 	if len(e.Elif) > 0 {
 		return c.compileIf(&If{e.Elif[0].Cond, e.Elif[0].Then, e.Elif[1:], e.Else})
 	}
@@ -686,7 +692,7 @@ func (c *compiler) compileIf(e *If) error {
 func (c *compiler) compileTry(e *Try) error {
 	c.appendCodeInfo(e)
 	setforktrybegin := c.lazy(func() *code {
-		return &code{op: opforktrybegin, v: c.pc()}
+		return &code{op: opforktrybegin, v: len(c.codes)}
 	})
 	f := c.newScopeDepth()
 	if err := c.compileQuery(e.Body); err != nil {
@@ -695,7 +701,7 @@ func (c *compiler) compileTry(e *Try) error {
 	f()
 	c.append(&code{op: opforktryend})
 	defer c.lazy(func() *code {
-		return &code{op: opjump, v: c.pc()}
+		return &code{op: opjump, v: len(c.codes)}
 	})()
 	setforktrybegin()
 	if e.Catch != nil {
@@ -709,9 +715,9 @@ func (c *compiler) compileTry(e *Try) error {
 func (c *compiler) compileReduce(e *Reduce) error {
 	c.appendCodeInfo(e)
 	defer c.newScopeDepth()()
-	defer c.lazy(func() *code {
-		return &code{op: opfork, v: c.pc() - 2}
-	})()
+	setfork := c.lazy(func() *code {
+		return &code{op: opfork, v: len(c.codes)}
+	})
 	c.append(&code{op: opdup})
 	v := c.newVariable()
 	f := c.newScopeDepth()
@@ -723,7 +729,7 @@ func (c *compiler) compileReduce(e *Reduce) error {
 	if err := c.compileTerm(e.Term); err != nil {
 		return err
 	}
-	if _, err := c.compilePattern(e.Pattern); err != nil {
+	if _, err := c.compilePattern(nil, e.Pattern); err != nil {
 		return err
 	}
 	c.append(&code{op: opload, v: v})
@@ -734,6 +740,7 @@ func (c *compiler) compileReduce(e *Reduce) error {
 	f()
 	c.append(&code{op: opstore, v: v})
 	c.append(&code{op: opbacktrack})
+	setfork()
 	c.append(&code{op: oppop})
 	c.append(&code{op: opload, v: v})
 	return nil
@@ -753,7 +760,7 @@ func (c *compiler) compileForeach(e *Foreach) error {
 	if err := c.compileTerm(e.Term); err != nil {
 		return err
 	}
-	if _, err := c.compilePattern(e.Pattern); err != nil {
+	if _, err := c.compilePattern(nil, e.Pattern); err != nil {
 		return err
 	}
 	c.append(&code{op: opload, v: v})
@@ -801,7 +808,7 @@ func (c *compiler) compileTerm(e *Term) error {
 	if len(e.SuffixList) > 0 {
 		s := e.SuffixList[len(e.SuffixList)-1]
 		t := *e // clone without changing e
-		(&t).SuffixList = t.SuffixList[:len(e.SuffixList)-1]
+		t.SuffixList = t.SuffixList[:len(e.SuffixList)-1]
 		return c.compileTermSuffix(&t, s)
 	}
 	switch e.Type {
@@ -827,11 +834,7 @@ func (c *compiler) compileTerm(e *Term) error {
 	case TermTypeArray:
 		return c.compileArray(e.Array)
 	case TermTypeNumber:
-		v := normalizeNumber(json.Number(e.Number))
-		if err, ok := v.(error); ok {
-			return err
-		}
-		c.append(&code{op: opconst, v: v})
+		c.append(&code{op: opconst, v: toNumber(e.Number)})
 		return nil
 	case TermTypeUnary:
 		return c.compileUnary(e.Unary)
@@ -860,10 +863,15 @@ func (c *compiler) compileTerm(e *Term) error {
 }
 
 func (c *compiler) compileIndex(e *Term, x *Index) error {
-	c.appendCodeInfo(x)
-	if x.Name != "" {
-		return c.compileCall("_index", []*Query{{Term: e}, {Term: &Term{Type: TermTypeString, Str: &String{Str: x.Name}}}})
+	if k := x.toIndexKey(); k != nil {
+		if err := c.compileTerm(e); err != nil {
+			return err
+		}
+		c.appendCodeInfo(x)
+		c.append(&code{op: opindex, v: k})
+		return nil
 	}
+	c.appendCodeInfo(x)
 	if x.Str != nil {
 		return c.compileCall("_index", []*Query{{Term: e}, {Term: &Term{Type: TermTypeString, Str: x.Str}}})
 	}
@@ -880,12 +888,11 @@ func (c *compiler) compileIndex(e *Term, x *Index) error {
 }
 
 func (c *compiler) compileFunc(e *Func) error {
-	name := e.Name
 	if len(e.Args) == 0 {
-		if f, v := c.lookupFuncOrVariable(name); f != nil {
+		if f, v := c.lookupFuncOrVariable(e.Name); f != nil {
 			return c.compileCallPc(f, e.Args)
 		} else if v != nil {
-			if name[0] == '$' {
+			if e.Name[0] == '$' {
 				c.append(&code{op: oppop})
 				c.append(&code{op: opload, v: v.index})
 			} else {
@@ -893,7 +900,7 @@ func (c *compiler) compileFunc(e *Func) error {
 				c.append(&code{op: opcallpc})
 			}
 			return nil
-		} else if name == "$ENV" || name == "env" {
+		} else if e.Name == "$ENV" || e.Name == "env" {
 			env := make(map[string]interface{})
 			if c.environLoader != nil {
 				for _, kv := range c.environLoader() {
@@ -904,35 +911,33 @@ func (c *compiler) compileFunc(e *Func) error {
 			}
 			c.append(&code{op: opconst, v: env})
 			return nil
-		} else if name[0] == '$' {
-			return &variableNotFoundError{name}
+		} else if e.Name[0] == '$' {
+			return &variableNotFoundError{e.Name}
 		}
 	} else {
 		for i := len(c.scopes) - 1; i >= 0; i-- {
 			s := c.scopes[i]
 			for j := len(s.funcs) - 1; j >= 0; j-- {
-				if f := s.funcs[j]; f.name == name && f.argcnt == len(e.Args) {
+				if f := s.funcs[j]; f.name == e.Name && f.argcnt == len(e.Args) {
 					return c.compileCallPc(f, e.Args)
 				}
 			}
 		}
 	}
-	if name[0] == '_' {
-		name = name[1:]
+	if f := c.lookupBuiltin(e.Name, len(e.Args)); f != nil {
+		return c.compileCallPc(f, e.Args)
 	}
-	if fds, ok := builtinFuncDefs[name]; ok {
+	if fds, ok := builtinFuncDefs[e.Name]; ok {
 		for _, fd := range fds {
 			if len(fd.Args) == len(e.Args) {
 				if err := c.compileFuncDef(fd, true); err != nil {
 					return err
 				}
+				break
 			}
 		}
-		s := c.scopes[0]
-		for i := len(s.funcs) - 1; i >= 0; i-- {
-			if f := s.funcs[i]; f.name == e.Name && f.argcnt == len(e.Args) {
-				return c.compileCallPc(f, e.Args)
-			}
+		if f := c.lookupBuiltin(e.Name, len(e.Args)); f != nil {
+			return c.compileCallPc(f, e.Args)
 		}
 	}
 	if fn, ok := internalFuncs[e.Name]; ok && fn.accept(len(e.Args)) {
@@ -985,7 +990,7 @@ func (c *compiler) compileFunc(e *Func) error {
 			return err
 		}
 		if fn.iter {
-			c.append(&code{op: opeach})
+			c.append(&code{op: opiter})
 		}
 		return nil
 	}
@@ -1138,61 +1143,57 @@ func (c *compiler) compileObject(e *Object) error {
 }
 
 func (c *compiler) compileObjectKeyVal(v [2]int, kv *ObjectKeyVal) error {
-	if kv.KeyOnly != "" {
-		if kv.KeyOnly[0] == '$' {
-			c.append(&code{op: oppush, v: kv.KeyOnly[1:]})
-			c.append(&code{op: opload, v: v})
-			return c.compileFunc(&Func{Name: kv.KeyOnly})
-		}
-		c.append(&code{op: oppush, v: kv.KeyOnly})
-		c.append(&code{op: opload, v: v})
-		return c.compileIndex(&Term{Type: TermTypeIdentity}, &Index{Name: kv.KeyOnly})
-	} else if kv.KeyOnlyString != nil {
-		c.append(&code{op: opload, v: v})
-		if err := c.compileString(kv.KeyOnlyString, nil); err != nil {
-			return err
-		}
-		c.append(&code{op: opdup})
-		c.append(&code{op: opload, v: v})
-		c.append(&code{op: opload, v: v})
-		// ref: compileCall
-		c.append(&code{op: opcall, v: [3]interface{}{internalFuncs["_index"].callback, 2, "_index"}})
-		return nil
-	} else {
-		if kv.KeyQuery != nil {
-			c.append(&code{op: opload, v: v})
-			f := c.newScopeDepth()
-			if err := c.compileQuery(kv.KeyQuery); err != nil {
-				return err
+	if key := kv.Key; key != "" {
+		if key[0] == '$' {
+			if kv.Val == nil { // {$foo} == {foo:$foo}
+				c.append(&code{op: oppush, v: key[1:]})
 			}
-			f()
-		} else if kv.KeyString != nil {
 			c.append(&code{op: opload, v: v})
-			if err := c.compileString(kv.KeyString, nil); err != nil {
+			if err := c.compileFunc(&Func{Name: key}); err != nil {
 				return err
 			}
-			if d := c.codes[len(c.codes)-1]; d.op == opconst {
-				c.codes[len(c.codes)-2] = &code{op: oppush, v: d.v}
-				c.codes = c.codes[:len(c.codes)-1]
+		} else {
+			c.append(&code{op: oppush, v: key})
+			if kv.Val == nil { // {foo} == {foo:.foo}
+				c.append(&code{op: opload, v: v})
+				c.append(&code{op: opindex, v: key})
+			}
+		}
+	} else if key := kv.KeyString; key != nil {
+		if key.Queries == nil {
+			c.append(&code{op: oppush, v: key.Str})
+			if kv.Val == nil { // {"foo"} == {"foo":.["foo"]}
+				c.append(&code{op: opload, v: v})
+				c.append(&code{op: opindex, v: key.Str})
 			}
-		} else if kv.Key[0] == '$' {
+		} else {
 			c.append(&code{op: opload, v: v})
-			if err := c.compileFunc(&Func{Name: kv.Key}); err != nil {
+			if err := c.compileString(key, nil); err != nil {
 				return err
 			}
-		} else {
-			c.append(&code{op: oppush, v: kv.Key})
+			if kv.Val == nil {
+				c.append(&code{op: opdup})
+				c.append(&code{op: opload, v: v})
+				c.append(&code{op: oppush, v: nil})
+				// ref: compileCall
+				c.append(&code{op: opcall, v: [3]interface{}{internalFuncs["_index"].callback, 2, "_index"}})
+			}
 		}
+	} else if kv.KeyQuery != nil {
 		c.append(&code{op: opload, v: v})
-		return c.compileObjectVal(kv.Val)
-	}
-}
-
-func (c *compiler) compileObjectVal(e *ObjectVal) error {
-	for _, e := range e.Queries {
-		if err := c.compileQuery(e); err != nil {
+		f := c.newScopeDepth()
+		if err := c.compileQuery(kv.KeyQuery); err != nil {
 			return err
 		}
+		f()
+	}
+	if kv.Val != nil {
+		c.append(&code{op: opload, v: v})
+		for _, e := range kv.Val.Queries {
+			if err := c.compileQuery(e); err != nil {
+				return err
+			}
+		}
 	}
 	return nil
 }
@@ -1207,18 +1208,16 @@ func (c *compiler) compileArray(e *Array) error {
 	arr := c.newVariable()
 	c.append(&code{op: opstore, v: arr})
 	pc := len(c.codes)
-	c.append(&code{op: opfork})
-	defer func() {
-		if pc < len(c.codes) {
-			c.codes[pc].v = c.pc() - 2
-		}
-	}()
+	setfork := c.lazy(func() *code {
+		return &code{op: opfork, v: len(c.codes)}
+	})
 	defer c.newScopeDepth()()
 	if err := c.compileQuery(e.Query); err != nil {
 		return err
 	}
 	c.append(&code{op: opappend, v: arr})
 	c.append(&code{op: opbacktrack})
+	setfork()
 	c.append(&code{op: oppop})
 	c.append(&code{op: opload, v: arr})
 	if e.Query.Op == OpPipe {
@@ -1247,6 +1246,10 @@ func (c *compiler) compileArray(e *Array) error {
 
 func (c *compiler) compileUnary(e *Unary) error {
 	c.appendCodeInfo(e)
+	if v := e.toNumber(); v != nil {
+		c.append(&code{op: opconst, v: v})
+		return nil
+	}
 	if err := c.compileTerm(e.Term); err != nil {
 		return err
 	}
@@ -1328,14 +1331,14 @@ func (c *compiler) compileTermSuffix(e *Term, s *Suffix) error {
 		if err := c.compileTerm(e); err != nil {
 			return err
 		}
-		c.append(&code{op: opeach})
+		c.append(&code{op: opiter})
 		return nil
 	} else if s.Optional {
 		if len(e.SuffixList) > 0 {
-			if u, ok := e.SuffixList[len(e.SuffixList)-1].toTerm(); ok {
-				t := *e // clone without changing e
-				(&t).SuffixList = t.SuffixList[:len(e.SuffixList)-1]
-				if err := c.compileTerm(&t); err != nil {
+			if u := e.SuffixList[len(e.SuffixList)-1].toTerm(); u != nil {
+				// no need to clone (ref: compileTerm)
+				e.SuffixList = e.SuffixList[:len(e.SuffixList)-1]
+				if err := c.compileTerm(e); err != nil {
 					return err
 				}
 				e = u
@@ -1343,12 +1346,7 @@ func (c *compiler) compileTermSuffix(e *Term, s *Suffix) error {
 		}
 		return c.compileTry(&Try{Body: &Query{Term: e}})
 	} else if s.Bind != nil {
-		c.append(&code{op: opdup})
-		c.append(&code{op: opexpbegin})
-		if err := c.compileTerm(e); err != nil {
-			return err
-		}
-		return c.compileBind(s.Bind)
+		return c.compileBind(e, s.Bind)
 	} else {
 		return fmt.Errorf("invalid suffix: %s", s)
 	}
@@ -1365,7 +1363,7 @@ func (c *compiler) compileCall(name string, args []*Query) error {
 		return err
 	}
 	if fn.iter {
-		c.append(&code{op: opeach})
+		c.append(&code{op: opiter})
 	}
 	return nil
 }
@@ -1380,22 +1378,22 @@ func (c *compiler) compileCallInternal(
 		c.append(&code{op: opcall, v: fn})
 		return nil
 	}
-	idx := c.newVariable()
-	c.append(&code{op: opstore, v: idx})
-	if indexing && len(args) > 1 {
+	v := c.newVariable()
+	c.append(&code{op: opstore, v: v})
+	if indexing {
 		c.append(&code{op: opexpbegin})
 	}
 	for i := len(args) - 1; i >= 0; i-- {
-		pc := c.pc() + 1 // skip opjump (ref: compileFuncDef)
+		pc := len(c.codes) + 1 // skip opjump (ref: compileFuncDef)
 		name := "lambda:" + strconv.Itoa(pc)
 		if err := c.compileFuncDef(&FuncDef{Name: name, Body: args[i]}, false); err != nil {
 			return err
 		}
 		if internal {
-			switch c.pc() - pc {
+			switch len(c.codes) - pc {
 			case 2: // optimize identity argument (opscope, opret)
 				j := len(c.codes) - 3
-				c.codes[j] = &code{op: opload, v: idx}
+				c.codes[j] = &code{op: opload, v: v}
 				c.codes = c.codes[:j+1]
 				s := c.scopes[len(c.scopes)-1]
 				s.funcs = s.funcs[:len(s.funcs)-1]
@@ -1406,7 +1404,7 @@ func (c *compiler) compileCallInternal(
 					c.codes[j] = &code{op: oppush, v: c.codes[j+2].v}
 					c.codes = c.codes[:j+1]
 				} else {
-					c.codes[j] = &code{op: opload, v: idx}
+					c.codes[j] = &code{op: opload, v: v}
 					c.codes[j+1] = c.codes[j+2]
 					c.codes = c.codes[:j+2]
 				}
@@ -1414,7 +1412,7 @@ func (c *compiler) compileCallInternal(
 				s.funcs = s.funcs[:len(s.funcs)-1]
 				c.deleteCodeInfo(name)
 			default:
-				c.append(&code{op: opload, v: idx})
+				c.append(&code{op: opload, v: v})
 				c.append(&code{op: oppushpc, v: pc})
 				c.append(&code{op: opcallpc})
 			}
@@ -1430,7 +1428,11 @@ func (c *compiler) compileCallInternal(
 			}
 		}
 	}
-	c.append(&code{op: opload, v: idx})
+	if indexing {
+		c.append(&code{op: oppush, v: nil})
+	} else {
+		c.append(&code{op: opload, v: v})
+	}
 	c.append(&code{op: opcall, v: fn})
 	return nil
 }
@@ -1439,10 +1441,6 @@ func (c *compiler) append(code *code) {
 	c.codes = append(c.codes, code)
 }
 
-func (c *compiler) pc() int {
-	return len(c.codes)
-}
-
 func (c *compiler) lazy(f func() *code) func() {
 	i := len(c.codes)
 	c.codes = append(c.codes, nil)
diff --git a/compiler_test.go b/compiler_test.go
index 86a13df..0a2fac9 100644
--- a/compiler_test.go
+++ b/compiler_test.go
@@ -105,7 +105,7 @@ func ExampleCode_RunWithContext() {
 }
 
 func TestCodeCompile_OptimizeConstants(t *testing.T) {
-	query, err := gojq.Parse(`[1,{foo:2,"bar":3},[4]]`)
+	query, err := gojq.Parse(`[1,{foo:2,"bar":+3},[-4]]`)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -123,7 +123,61 @@ func TestCodeCompile_OptimizeConstants(t *testing.T) {
 			break
 		}
 		if expected := []interface{}{
-			1, map[string]interface{}{"foo": 2, "bar": 3}, []interface{}{4},
+			1, map[string]interface{}{"foo": 2, "bar": 3}, []interface{}{-4},
+		}; !reflect.DeepEqual(got, expected) {
+			t.Errorf("expected: %v, got: %v", expected, got)
+		}
+	}
+}
+
+func TestCodeCompile_OptimizeIndex(t *testing.T) {
+	query, err := gojq.Parse(`.foo."bar".["baz"].[-1].""`)
+	if err != nil {
+		t.Fatal(err)
+	}
+	code, err := gojq.Compile(query)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if got, expected := reflect.ValueOf(code).Elem().FieldByName("codes").Len(), 7; expected != got {
+		t.Errorf("expected: %v, got: %v", expected, got)
+	}
+	iter := code.Run(nil)
+	for {
+		got, ok := iter.Next()
+		if !ok {
+			break
+		}
+		if got != nil {
+			t.Errorf("expected: %v, got: %v", nil, got)
+		}
+	}
+}
+
+func TestCodeCompile_OptimizeIndexAssign(t *testing.T) {
+	query, err := gojq.Parse(`.foo."bar".["baz"].[0]."" = 0`)
+	if err != nil {
+		t.Fatal(err)
+	}
+	code, err := gojq.Compile(query)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if got, expected := reflect.ValueOf(code).Elem().FieldByName("codes").Len(), 8; expected != got {
+		t.Errorf("expected: %v, got: %v", expected, got)
+	}
+	iter := code.Run(nil)
+	for {
+		got, ok := iter.Next()
+		if !ok {
+			break
+		}
+		if expected := map[string]interface{}{
+			"foo": map[string]interface{}{
+				"bar": map[string]interface{}{
+					"baz": []interface{}{map[string]interface{}{"": 0}},
+				},
+			},
 		}; !reflect.DeepEqual(got, expected) {
 			t.Errorf("expected: %v, got: %v", expected, got)
 		}
diff --git a/debian/changelog b/debian/changelog
index 1365af9..8da729e 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+gojq (0.12.7+git20220416.1.0e045e2-1) UNRELEASED; urgency=low
+
+  * New upstream snapshot.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Sat, 16 Apr 2022 01:24:15 -0000
+
 gojq (0.12.7-1) unstable; urgency=medium
 
   * New upstream version 0.12.7
diff --git a/debug.go b/debug.go
index 4a346fb..5ebb556 100644
--- a/debug.go
+++ b/debug.go
@@ -1,5 +1,5 @@
-//go:build debug
-// +build debug
+//go:build gojq_debug
+// +build gojq_debug
 
 package gojq
 
@@ -47,7 +47,7 @@ func (c *compiler) appendCodeInfo(x interface{}) {
 	if c.codes[len(c.codes)-1] != nil && c.codes[len(c.codes)-1].op == opret && strings.HasPrefix(name, "end of ") {
 		diff = -1
 	}
-	c.codeinfos = append(c.codeinfos, codeinfo{name, c.pc() + diff})
+	c.codeinfos = append(c.codeinfos, codeinfo{name, len(c.codes) + diff})
 }
 
 func (c *compiler) deleteCodeInfo(name string) {
@@ -196,6 +196,8 @@ func debugValue(v interface{}) string {
 	switch v := v.(type) {
 	case Iter:
 		return fmt.Sprintf("gojq.Iter(%#v)", v)
+	case []pathValue:
+		return fmt.Sprintf("[]gojq.pathValue(%v)", v)
 	case [2]int:
 		return fmt.Sprintf("[%d,%d]", v[0], v[1])
 	case [3]int:
diff --git a/deepequal.go b/deepequal.go
deleted file mode 100644
index 37c56e4..0000000
--- a/deepequal.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package gojq
-
-import (
-	"math"
-	"math/big"
-)
-
-func deepEqual(l, r interface{}) bool {
-	return binopTypeSwitch(l, r,
-		func(l, r int) interface{} {
-			return l == r
-		},
-		func(l, r float64) interface{} {
-			return l == r || math.IsNaN(l) && math.IsNaN(r)
-		},
-		func(l, r *big.Int) interface{} {
-			return l.Cmp(r) == 0
-		},
-		func(l, r string) interface{} {
-			return l == r
-		},
-		func(l, r []interface{}) interface{} {
-			if len(l) != len(r) {
-				return false
-			}
-			for i, v := range l {
-				if !deepEqual(v, r[i]) {
-					return false
-				}
-			}
-			return true
-		},
-		func(l, r map[string]interface{}) interface{} {
-			if len(l) != len(r) {
-				return false
-			}
-			for k, v := range l {
-				if !deepEqual(v, r[k]) {
-					return false
-				}
-			}
-			return true
-		},
-		func(l, r interface{}) interface{} {
-			return l == r
-		},
-	).(bool)
-}
diff --git a/encoder.go b/encoder.go
index c7905f9..504d932 100644
--- a/encoder.go
+++ b/encoder.go
@@ -18,9 +18,9 @@ import (
 // string, []interface{} and map[string]interface{}) because these are the
 // possible types a gojq iterator can emit. This method marshals NaN to null,
 // truncates infinities to (+|-) math.MaxFloat64, uses \b and \f in strings,
-// and does not escape '<' and '>' for embedding in HTML. These behaviors are
-// based on the marshaler of jq command and different from Go standard library
-// method json.Marshal.
+// and does not escape '<', '>', '&', '\u2028', and '\u2029'. These behaviors
+// are based on the marshaler of jq command, and different from json.Marshal in
+// the Go standard library. Note that the result is not safe to embed in HTML.
 func Marshal(v interface{}) ([]byte, error) {
 	var b bytes.Buffer
 	(&encoder{w: &b}).encode(v)
@@ -33,6 +33,10 @@ func jsonMarshal(v interface{}) string {
 	return sb.String()
 }
 
+func jsonEncodeString(sb *strings.Builder, v string) {
+	(&encoder{w: sb}).encodeString(v)
+}
+
 type encoder struct {
 	w interface {
 		io.Writer
@@ -65,7 +69,7 @@ func (e *encoder) encode(v interface{}) {
 	case map[string]interface{}:
 		e.encodeMap(v)
 	default:
-		panic(fmt.Sprintf("invalid value: %v", v))
+		panic(fmt.Sprintf("invalid type: %T (%v)", v, v))
 	}
 }
 
@@ -101,30 +105,31 @@ func (e *encoder) encodeString(s string) {
 	start := 0
 	for i := 0; i < len(s); {
 		if b := s[i]; b < utf8.RuneSelf {
-			if ']' <= b && b <= '~' || '#' <= b && b <= '[' || b == ' ' || b == '!' {
+			if ' ' <= b && b <= '~' && b != '"' && b != '\\' {
 				i++
 				continue
 			}
 			if start < i {
 				e.w.WriteString(s[start:i])
 			}
-			e.w.WriteByte('\\')
 			switch b {
-			case '\\', '"':
-				e.w.WriteByte(b)
+			case '"':
+				e.w.WriteString(`\"`)
+			case '\\':
+				e.w.WriteString(`\\`)
 			case '\b':
-				e.w.WriteByte('b')
+				e.w.WriteString(`\b`)
 			case '\f':
-				e.w.WriteByte('f')
+				e.w.WriteString(`\f`)
 			case '\n':
-				e.w.WriteByte('n')
+				e.w.WriteString(`\n`)
 			case '\r':
-				e.w.WriteByte('r')
+				e.w.WriteString(`\r`)
 			case '\t':
-				e.w.WriteByte('t')
+				e.w.WriteString(`\t`)
 			default:
 				const hex = "0123456789abcdef"
-				e.w.WriteString("u00")
+				e.w.WriteString(`\u00`)
 				e.w.WriteByte(hex[b>>4])
 				e.w.WriteByte(hex[b&0xF])
 			}
diff --git a/error.go b/error.go
index c13e977..a95a4a5 100644
--- a/error.go
+++ b/error.go
@@ -141,11 +141,11 @@ func (err *exitCodeError) IsHaltError() bool {
 	return err.halt
 }
 
-type funcContainsError struct {
+type containsTypeError struct {
 	l, r interface{}
 }
 
-func (err *funcContainsError) Error() string {
+func (err *containsTypeError) Error() string {
 	return "cannot check contains(" + previewValue(err.r) + "): " + typeErrorPreview(err.l)
 }
 
@@ -157,6 +157,22 @@ func (err *hasKeyTypeError) Error() string {
 	return "cannot check whether " + typeErrorPreview(err.l) + " has a key: " + typeErrorPreview(err.r)
 }
 
+type flattenDepthError struct {
+	v float64
+}
+
+func (err *flattenDepthError) Error() string {
+	return "flatten depth must not be negative: " + typeErrorPreview(err.v)
+}
+
+type joinTypeError struct {
+	v interface{}
+}
+
+func (err *joinTypeError) Error() string {
+	return "cannot join: " + typeErrorPreview(err.v)
+}
+
 type unaryTypeError struct {
 	name string
 	v    interface{}
@@ -343,7 +359,7 @@ func typeof(v interface{}) string {
 	case map[string]interface{}:
 		return "object"
 	default:
-		panic(fmt.Sprintf("invalid value: %v", v))
+		panic(fmt.Sprintf("invalid type: %T (%v)", v, v))
 	}
 }
 
@@ -383,7 +399,7 @@ func (w *limitedWriter) String() string {
 func jsonLimitedMarshal(v interface{}, n int) (s string) {
 	w := &limitedWriter{buf: make([]byte, n)}
 	defer func() {
-		recover()
+		_ = recover()
 		s = w.String()
 	}()
 	(&encoder{w: w}).encode(v)
diff --git a/execute.go b/execute.go
index d861c62..a79aace 100644
--- a/execute.go
+++ b/execute.go
@@ -2,7 +2,8 @@ package gojq
 
 import (
 	"context"
-	"fmt"
+	"math"
+	"reflect"
 	"sort"
 )
 
@@ -42,9 +43,9 @@ loop:
 		case oppop:
 			env.pop()
 		case opdup:
-			x := env.pop()
-			env.push(x)
-			env.push(x)
+			v := env.pop()
+			env.push(v)
+			env.push(v)
 		case opconst:
 			env.pop()
 			env.push(code.v)
@@ -153,6 +154,24 @@ loop:
 				pc = code.v.(int)
 				goto loop
 			}
+		case opindex:
+			if backtrack {
+				break loop
+			}
+			p, v := code.v, env.pop()
+			w := funcIndex2(nil, v, p)
+			if e, ok := w.(error); ok {
+				err = e
+				break loop
+			}
+			env.push(w)
+			if !env.paths.empty() && env.expdepth == 0 {
+				if !env.pathIntact(v) {
+					err = &invalidPathError{v}
+					break loop
+				}
+				env.paths.push(pathValue{path: p, value: w})
+			}
 		case opcall:
 			if backtrack {
 				break loop
@@ -175,14 +194,31 @@ loop:
 					break loop
 				}
 				env.push(w)
-				if !env.paths.empty() {
-					var ps []interface{}
-					ps, err = env.pathEntries(v[2].(string), x, args)
-					if err != nil {
-						break loop
-					}
-					for _, p := range ps {
-						env.paths.push(pathValue{path: p, value: w})
+				if !env.paths.empty() && env.expdepth == 0 {
+					switch v[2].(string) {
+					case "_index":
+						if x = args[0]; !env.pathIntact(x) {
+							err = &invalidPathError{x}
+							break loop
+						}
+						env.paths.push(pathValue{path: args[1], value: w})
+					case "_slice":
+						if x = args[0]; !env.pathIntact(x) {
+							err = &invalidPathError{x}
+							break loop
+						}
+						env.paths.push(pathValue{
+							path:  map[string]interface{}{"start": args[2], "end": args[1]},
+							value: w,
+						})
+					case "getpath":
+						if !env.pathIntact(x) {
+							err = &invalidPathError{x}
+							break loop
+						}
+						for _, p := range args[0].([]interface{}) {
+							env.paths.push(pathValue{path: p, value: w})
+						}
 					}
 				}
 			default:
@@ -199,7 +235,7 @@ loop:
 			goto loop
 		case opscope:
 			xs := code.v.([3]int)
-			var saveindex, outerindex, limit int
+			var saveindex, outerindex int
 			if index == env.scopes.index {
 				if callpc >= 0 {
 					saveindex = index
@@ -207,7 +243,7 @@ loop:
 					callpc, saveindex = env.popscope()
 				}
 			} else {
-				env.scopes.save(&saveindex, &limit)
+				saveindex, _ = env.scopes.save()
 				env.scopes.index = index
 			}
 			if outerindex = index; outerindex >= 0 {
@@ -230,7 +266,7 @@ loop:
 			if env.scopes.empty() {
 				return env.pop(), true
 			}
-		case opeach:
+		case opiter:
 			if err != nil {
 				break loop
 			}
@@ -240,8 +276,7 @@ loop:
 			case []pathValue:
 				xs = v
 			case []interface{}:
-				if !env.paths.empty() && env.expdepth == 0 &&
-					!deepEqual(v, env.paths.top().(pathValue).value) {
+				if !env.paths.empty() && env.expdepth == 0 && !env.pathIntact(v) {
 					err = &invalidPathIterError{v}
 					break loop
 				}
@@ -253,8 +288,7 @@ loop:
 					xs[i] = pathValue{path: i, value: v}
 				}
 			case map[string]interface{}:
-				if !env.paths.empty() && env.expdepth == 0 &&
-					!deepEqual(v, env.paths.top().(pathValue).value) {
+				if !env.paths.empty() && env.expdepth == 0 && !env.pathIntact(v) {
 					err = &invalidPathIterError{v}
 					break loop
 				}
@@ -289,6 +323,7 @@ loop:
 				break loop
 			default:
 				err = &iteratorError{v}
+				env.push(emptyIter{})
 				break loop
 			}
 			if len(xs) > 1 {
@@ -312,18 +347,13 @@ loop:
 			if backtrack {
 				break loop
 			}
-			if env.expdepth > 0 {
-				panic(fmt.Sprintf("unexpected expdepth: %d", env.expdepth))
-			}
 			env.pop()
-			x := env.pop()
-			if deepEqual(x, env.paths.top().(pathValue).value) {
-				env.push(env.poppaths())
-				env.expdepth = env.paths.pop().(int)
-			} else {
-				err = &invalidPathError{x}
+			if v := env.pop(); !env.pathIntact(v) {
+				err = &invalidPathError{v}
 				break loop
 			}
+			env.push(env.poppaths())
+			env.expdepth = env.paths.pop().(int)
 		default:
 			panic(code.op)
 		}
@@ -357,9 +387,9 @@ func (env *env) popscope() (int, int) {
 
 func (env *env) pushfork(pc int) {
 	f := fork{pc: pc, expdepth: env.expdepth}
-	env.stack.save(&f.stackindex, &f.stacklimit)
-	env.scopes.save(&f.scopeindex, &f.scopelimit)
-	env.paths.save(&f.pathindex, &f.pathlimit)
+	f.stackindex, f.stacklimit = env.stack.save()
+	f.scopeindex, f.scopelimit = env.scopes.save()
+	f.pathindex, f.pathlimit = env.paths.save()
 	env.forks = append(env.forks, f)
 	env.debugForks(pc, ">>>")
 }
@@ -389,32 +419,21 @@ type pathValue struct {
 	path, value interface{}
 }
 
-func (env *env) pathEntries(name string, x interface{}, args []interface{}) ([]interface{}, error) {
-	switch name {
-	case "_index":
-		if env.expdepth > 0 {
-			return nil, nil
-		} else if !deepEqual(args[0], env.paths.top().(pathValue).value) {
-			return nil, &invalidPathError{x}
-		}
-		return []interface{}{args[1]}, nil
-	case "_slice":
-		if env.expdepth > 0 {
-			return nil, nil
-		} else if !deepEqual(args[0], env.paths.top().(pathValue).value) {
-			return nil, &invalidPathError{x}
+func (env *env) pathIntact(v interface{}) bool {
+	w := env.paths.top().(pathValue).value
+	switch v := v.(type) {
+	case []interface{}, map[string]interface{}:
+		switch w.(type) {
+		case []interface{}, map[string]interface{}:
+			v, w := reflect.ValueOf(v), reflect.ValueOf(w)
+			return v.Pointer() == w.Pointer() && v.Len() == w.Len()
 		}
-		return []interface{}{map[string]interface{}{"start": args[2], "end": args[1]}}, nil
-	case "getpath":
-		if env.expdepth > 0 {
-			return nil, nil
-		} else if !deepEqual(x, env.paths.top().(pathValue).value) {
-			return nil, &invalidPathError{x}
+	case float64:
+		if w, ok := w.(float64); ok {
+			return v == w || math.IsNaN(v) && math.IsNaN(w)
 		}
-		return args[0].([]interface{}), nil
-	default:
-		return nil, nil
 	}
+	return v == w
 }
 
 func (env *env) poppaths() []interface{} {
diff --git a/func.go b/func.go
index ca4caa6..5e9287d 100644
--- a/func.go
+++ b/func.go
@@ -51,12 +51,21 @@ func init() {
 		"utf8bytelength": argFunc0(funcUtf8ByteLength),
 		"keys":           argFunc0(funcKeys),
 		"has":            argFunc1(funcHas),
+		"to_entries":     argFunc0(funcToEntries),
+		"from_entries":   argFunc0(funcFromEntries),
 		"add":            argFunc0(funcAdd),
 		"tonumber":       argFunc0(funcToNumber),
 		"tostring":       argFunc0(funcToString),
 		"type":           argFunc0(funcType),
 		"reverse":        argFunc0(funcReverse),
 		"contains":       argFunc1(funcContains),
+		"indices":        argFunc1(funcIndices),
+		"index":          argFunc1(funcIndex),
+		"rindex":         argFunc1(funcRindex),
+		"startswith":     argFunc1(funcStartsWith),
+		"endswith":       argFunc1(funcEndsWith),
+		"ltrimstr":       argFunc1(funcLtrimstr),
+		"rtrimstr":       argFunc1(funcRtrimstr),
 		"explode":        argFunc0(funcExplode),
 		"implode":        argFunc0(funcImplode),
 		"split":          {argcount1 | argcount2, false, funcSplit},
@@ -70,11 +79,8 @@ func init() {
 		"_tosh":          argFunc0(funcToSh),
 		"_tobase64":      argFunc0(funcToBase64),
 		"_tobase64d":     argFunc0(funcToBase64d),
-		"_index":         argFunc2(funcIndex),
+		"_index":         argFunc2(funcIndex2),
 		"_slice":         argFunc3(funcSlice),
-		"_indices":       argFunc1(funcIndices),
-		"_lindex":        argFunc1(funcLindex),
-		"_rindex":        argFunc1(funcRindex),
 		"_plus":          argFunc0(funcOpPlus),
 		"_negate":        argFunc0(funcOpNegate),
 		"_add":           argFunc2(funcOpAdd),
@@ -89,13 +95,18 @@ func init() {
 		"_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),
-		"_join":          argFunc1(funcJoin),
+		"join":           argFunc1(funcJoin),
 		"sin":            mathFunc("sin", math.Sin),
 		"cos":            mathFunc("cos", math.Cos),
 		"tan":            mathFunc("tan", math.Tan),
@@ -176,41 +187,41 @@ func init() {
 		"strptime":       argFunc1(funcStrptime),
 		"now":            argFunc0(funcNow),
 		"_match":         argFunc3(funcMatch),
+		"_capture":       argFunc0(funcCapture),
 		"error":          {argcount0 | argcount1, false, funcError},
 		"halt":           argFunc0(funcHalt),
 		"halt_error":     {argcount0 | argcount1, false, funcHaltError},
-		"_type_error":    argFunc1(internalfuncTypeError),
 	}
 }
 
-func argFunc0(fn func(interface{}) interface{}) function {
+func argFunc0(f func(interface{}) interface{}) function {
 	return function{
 		argcount0, false, func(v interface{}, _ []interface{}) interface{} {
-			return fn(v)
+			return f(v)
 		},
 	}
 }
 
-func argFunc1(fn func(_, _ interface{}) interface{}) function {
+func argFunc1(f func(_, _ interface{}) interface{}) function {
 	return function{
 		argcount1, false, func(v interface{}, args []interface{}) interface{} {
-			return fn(v, args[0])
+			return f(v, args[0])
 		},
 	}
 }
 
-func argFunc2(fn func(_, _, _ interface{}) interface{}) function {
+func argFunc2(f func(_, _, _ interface{}) interface{}) function {
 	return function{
 		argcount2, false, func(v interface{}, args []interface{}) interface{} {
-			return fn(v, args[0], args[1])
+			return f(v, args[0], args[1])
 		},
 	}
 }
 
-func argFunc3(fn func(_, _, _, _ interface{}) interface{}) function {
+func argFunc3(f func(_, _, _, _ interface{}) interface{}) function {
 	return function{
 		argcount3, false, func(v interface{}, args []interface{}) interface{} {
-			return fn(v, args[0], args[1], args[2])
+			return f(v, args[0], args[1], args[2])
 		},
 	}
 }
@@ -302,61 +313,118 @@ func funcKeys(v interface{}) interface{} {
 		}
 		return w
 	case map[string]interface{}:
-		w := make([]string, len(v))
-		var i int
-		for k := range v {
+		w := make([]interface{}, len(v))
+		for i, k := range keys(v) {
 			w[i] = k
-			i++
-		}
-		sort.Strings(w)
-		u := make([]interface{}, len(v))
-		for i, x := range w {
-			u[i] = x
 		}
-		return u
+		return w
 	default:
 		return &funcTypeError{"keys", v}
 	}
 }
 
+func keys(v map[string]interface{}) []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 interface{}) ([]interface{}, bool) {
+	switch v := v.(type) {
+	case []interface{}:
+		return v, true
+	case map[string]interface{}:
+		vs := make([]interface{}, len(v))
+		for i, k := range keys(v) {
+			vs[i] = v[k]
+		}
+		return vs, true
+	default:
+		return nil, false
+	}
+}
+
 func funcHas(v, x interface{}) interface{} {
 	switch v := v.(type) {
 	case []interface{}:
 		if x, ok := toInt(x); ok {
 			return 0 <= x && x < len(v)
 		}
-		return &hasKeyTypeError{v, x}
 	case map[string]interface{}:
-		switch x := x.(type) {
-		case string:
+		if x, ok := x.(string); ok {
 			_, ok := v[x]
 			return ok
-		default:
-			return &hasKeyTypeError{v, x}
 		}
 	case nil:
 		return false
-	default:
-		return &hasKeyTypeError{v, x}
 	}
+	return &hasKeyTypeError{v, x}
 }
 
-func funcAdd(v interface{}) interface{} {
-	if vs, ok := v.(map[string]interface{}); ok {
-		xs := make([]string, len(vs))
-		var i int
-		for k := range vs {
-			xs[i] = k
-			i++
-		}
-		sort.Strings(xs)
-		us := make([]interface{}, len(vs))
-		for i, x := range xs {
-			us[i] = vs[x]
+func funcToEntries(v interface{}) interface{} {
+	switch v := v.(type) {
+	case []interface{}:
+		w := make([]interface{}, len(v))
+		for i, x := range v {
+			w[i] = map[string]interface{}{"key": i, "value": x}
+		}
+		return w
+	case map[string]interface{}:
+		w := make([]interface{}, len(v))
+		for i, k := range keys(v) {
+			w[i] = map[string]interface{}{"key": k, "value": v[k]}
 		}
-		v = us
+		return w
+	default:
+		return &funcTypeError{"to_entries", v}
 	}
+}
+
+func funcFromEntries(v interface{}) interface{} {
 	vs, ok := v.([]interface{})
+	if !ok {
+		return &funcTypeError{"from_entries", v}
+	}
+	w := make(map[string]interface{}, len(vs))
+	for _, v := range vs {
+		switch v := v.(type) {
+		case map[string]interface{}:
+			var (
+				key   string
+				value interface{}
+				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 &objectKeyNotStringError{k}
+					}
+					break
+				}
+			}
+			if !ok {
+				return &objectKeyNotStringError{nil}
+			}
+			for _, k := range [2]string{"value", "Value"} {
+				if value, ok = v[k]; ok {
+					break
+				}
+			}
+			w[key] = value
+		default:
+			return &funcTypeError{"from_entries", v}
+		}
+	}
+	return w
+}
+
+func funcAdd(v interface{}) interface{} {
+	vs, ok := values(v)
 	if !ok {
 		return &funcTypeError{"add", v}
 	}
@@ -406,12 +474,16 @@ func funcToNumber(v interface{}) interface{} {
 		if !newLexer(v).validNumber() {
 			return fmt.Errorf("invalid number: %q", v)
 		}
-		return normalizeNumber(json.Number(v))
+		return toNumber(v)
 	default:
 		return &funcTypeError{"tonumber", v}
 	}
 }
 
+func toNumber(v string) interface{} {
+	return normalizeNumber(json.Number(v))
+}
+
 func funcToString(v interface{}) interface{} {
 	if s, ok := v.(string); ok {
 		return s
@@ -426,7 +498,7 @@ func funcType(v interface{}) interface{} {
 func funcReverse(v interface{}) interface{} {
 	vs, ok := v.([]interface{})
 	if !ok {
-		return &expectedArrayError{v}
+		return &funcTypeError{"reverse", v}
 	}
 	ws := make([]interface{}, len(vs))
 	for i, v := range vs {
@@ -436,59 +508,179 @@ func funcReverse(v interface{}) interface{} {
 }
 
 func funcContains(v, x interface{}) interface{} {
-	switch v := v.(type) {
-	case nil:
-		if x == nil {
-			return true
-		}
-	case bool:
-		switch x := x.(type) {
-		case bool:
-			if v == x {
-				return true
-			}
-		}
-	}
 	return binopTypeSwitch(v, x,
 		func(l, r int) interface{} { return l == r },
 		func(l, r float64) interface{} { return l == r },
 		func(l, r *big.Int) interface{} { return l.Cmp(r) == 0 },
 		func(l, r string) interface{} { return strings.Contains(l, r) },
 		func(l, r []interface{}) interface{} {
-			for _, x := range r {
-				var found bool
-				for _, y := range l {
-					if funcContains(y, x) == true {
-						found = true
-						break
+		R:
+			for _, r := range r {
+				for _, l := range l {
+					if funcContains(l, r) == true {
+						continue R
 					}
 				}
-				if !found {
-					return false
-				}
+				return false
 			}
 			return true
 		},
 		func(l, r map[string]interface{}) interface{} {
-			for k, rk := range r {
-				lk, ok := l[k]
-				if !ok {
-					return false
-				}
-				c := funcContains(lk, rk)
-				if _, ok := c.(error); ok {
-					return false
-				}
-				if c == false {
+			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 interface{}) interface{} { return &funcContainsError{l, r} },
+		func(l, r interface{}) interface{} {
+			if l == r {
+				return true
+			}
+			return &containsTypeError{l, r}
+		},
 	)
 }
 
+func funcIndices(v, x interface{}) interface{} {
+	return indexFunc(v, x, indices)
+}
+
+func indices(vs, xs []interface{}) interface{} {
+	var rs []interface{}
+	if len(xs) == 0 {
+		return rs
+	}
+	for i := 0; i < len(vs) && i < len(vs)-len(xs)+1; i++ {
+		var neq bool
+		for j, x := range xs {
+			if neq = compare(vs[i+j], x) != 0; neq {
+				break
+			}
+		}
+		if !neq {
+			rs = append(rs, i)
+		}
+	}
+	return rs
+}
+
+func funcIndex(v, x interface{}) interface{} {
+	return indexFunc(v, x, func(vs, xs []interface{}) interface{} {
+		if len(xs) == 0 {
+			return nil
+		}
+		for i := 0; i < len(vs) && i < len(vs)-len(xs)+1; i++ {
+			var neq bool
+			for j, x := range xs {
+				if neq = compare(vs[i+j], x) != 0; neq {
+					break
+				}
+			}
+			if !neq {
+				return i
+			}
+		}
+		return nil
+	})
+}
+
+func funcRindex(v, x interface{}) interface{} {
+	return indexFunc(v, x, func(vs, xs []interface{}) interface{} {
+		if len(xs) == 0 {
+			return nil
+		}
+		i := len(vs) - 1
+		if j := len(vs) - len(xs); j < i {
+			i = j
+		}
+		for ; i >= 0; i-- {
+			var neq bool
+			for j, x := range xs {
+				if neq = compare(vs[i+j], x) != 0; neq {
+					break
+				}
+			}
+			if !neq {
+				return i
+			}
+		}
+		return nil
+	})
+}
+
+func indexFunc(v, x interface{}, f func(_, _ []interface{}) interface{}) interface{} {
+	switch v := v.(type) {
+	case nil:
+		return nil
+	case []interface{}:
+		switch x := x.(type) {
+		case []interface{}:
+			return f(v, x)
+		default:
+			return f(v, []interface{}{x})
+		}
+	case string:
+		if x, ok := x.(string); ok {
+			return f(explode(v), explode(x))
+		}
+		return &expectedStringError{x}
+	default:
+		return &expectedArrayError{v}
+	}
+}
+
+func funcStartsWith(v, x interface{}) interface{} {
+	s, ok := v.(string)
+	if !ok {
+		return &funcTypeError{"startswith", v}
+	}
+	t, ok := x.(string)
+	if !ok {
+		return &funcTypeError{"startswith", x}
+	}
+	return strings.HasPrefix(s, t)
+}
+
+func funcEndsWith(v, x interface{}) interface{} {
+	s, ok := v.(string)
+	if !ok {
+		return &funcTypeError{"endswith", v}
+	}
+	t, ok := x.(string)
+	if !ok {
+		return &funcTypeError{"endswith", x}
+	}
+	return strings.HasSuffix(s, t)
+}
+
+func funcLtrimstr(v, x interface{}) interface{} {
+	s, ok := v.(string)
+	if !ok {
+		return v
+	}
+	t, ok := x.(string)
+	if !ok {
+		return v
+	}
+	return strings.TrimPrefix(s, t)
+}
+
+func funcRtrimstr(v, x interface{}) interface{} {
+	s, ok := v.(string)
+	if !ok {
+		return v
+	}
+	t, ok := x.(string)
+	if !ok {
+		return v
+	}
+	return strings.TrimSuffix(s, t)
+}
+
 func funcExplode(v interface{}) interface{} {
 	switch v := v.(type) {
 	case string:
@@ -499,10 +691,11 @@ func funcExplode(v interface{}) interface{} {
 }
 
 func explode(s string) []interface{} {
-	rs := []int32(s)
-	xs := make([]interface{}, len(rs))
-	for i, r := range rs {
+	xs := make([]interface{}, len([]rune(s)))
+	var i int
+	for _, r := range s {
 		xs[i] = int(r)
+		i++
 	}
 	return xs
 }
@@ -516,14 +709,14 @@ func funcImplode(v interface{}) interface{} {
 	}
 }
 
-func implode(v []interface{}) interface{} {
+func implode(vs []interface{}) interface{} {
 	var sb strings.Builder
-	sb.Grow(len(v))
-	for _, r := range v {
-		if r, ok := toInt(r); ok && 0 <= r && r <= utf8.MaxRune {
+	sb.Grow(len(vs))
+	for _, v := range vs {
+		if r, ok := toInt(v); ok && 0 <= r && r <= utf8.MaxRune {
 			sb.WriteRune(rune(r))
 		} else {
-			return &funcTypeError{"implode", v}
+			return &funcTypeError{"implode", vs}
 		}
 	}
 	return sb.String()
@@ -653,7 +846,7 @@ func funcToCSVTSV(typ string, v interface{}, sep string, escape func(string) str
 		}
 		return strings.Join(ys, sep)
 	default:
-		return &expectedArrayError{v}
+		return &funcTypeError{"@" + typ, v}
 	}
 }
 
@@ -678,23 +871,23 @@ func funcToSh(v interface{}) interface{} {
 	} else {
 		xs = []interface{}{v}
 	}
-	var s strings.Builder
+	var sb strings.Builder
 	for i, x := range xs {
 		if i > 0 {
-			s.WriteByte(' ')
+			sb.WriteByte(' ')
 		}
 		switch x := x.(type) {
 		case map[string]interface{}, []interface{}:
 			return &formatShError{x}
 		case string:
-			s.WriteByte('\'')
-			s.WriteString(strings.ReplaceAll(x, "'", `'\''`))
-			s.WriteByte('\'')
+			sb.WriteByte('\'')
+			sb.WriteString(strings.ReplaceAll(x, "'", `'\''`))
+			sb.WriteByte('\'')
 		default:
-			s.WriteString(jsonMarshal(x))
+			sb.WriteString(jsonMarshal(x))
 		}
 	}
-	return s.String()
+	return sb.String()
 }
 
 func funcToBase64(v interface{}) interface{} {
@@ -722,7 +915,7 @@ func funcToBase64d(v interface{}) interface{} {
 	}
 }
 
-func funcIndex(_, v, x interface{}) interface{} {
+func funcIndex2(_, v, x interface{}) interface{} {
 	switch x := x.(type) {
 	case string:
 		switch v := v.(type) {
@@ -734,23 +927,14 @@ func funcIndex(_, v, x interface{}) interface{} {
 			return &expectedObjectError{v}
 		}
 	case int, float64, *big.Int:
-		idx, _ := toInt(x)
+		i, _ := toInt(x)
 		switch v := v.(type) {
 		case nil:
 			return nil
 		case []interface{}:
-			return funcIndexSlice(nil, nil, &idx, v)
+			return index(v, i)
 		case string:
-			switch v := funcIndexSlice(nil, nil, &idx, explode(v)).(type) {
-			case []interface{}:
-				return implode(v)
-			case int:
-				return implode([]interface{}{v})
-			case nil:
-				return ""
-			default:
-				panic(v)
-			}
+			return indexString(v, i)
 		default:
 			return &expectedArrayError{v}
 		}
@@ -777,185 +961,117 @@ func funcIndex(_, v, x interface{}) interface{} {
 		}
 		return funcSlice(nil, v, end, start)
 	default:
-		return &objectKeyNotStringError{x}
+		switch v.(type) {
+		case []interface{}:
+			return &arrayIndexNotNumberError{x}
+		default:
+			return &objectKeyNotStringError{x}
+		}
 	}
 }
 
-func indices(vs, xs []interface{}) interface{} {
-	var rs []interface{}
-	if len(xs) == 0 {
-		return rs
+func index(vs []interface{}, i int) interface{} {
+	i = clampIndex(i, -1, len(vs))
+	if 0 <= i && i < len(vs) {
+		return vs[i]
 	}
-	for i := 0; i < len(vs) && i < len(vs)-len(xs)+1; i++ {
-		var neq bool
-		for j, y := range xs {
-			if neq = compare(vs[i+j], y) != 0; neq {
-				break
+	return nil
+}
+
+func indexString(s string, i int) interface{} {
+	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)
 			}
 		}
-		if !neq {
-			rs = append(rs, i)
-		}
 	}
-	return rs
+	return nil
 }
 
-func funcSlice(_, v, end, start interface{}) (r interface{}) {
-	if w, ok := v.(string); ok {
-		v = explode(w)
-		defer func() {
-			switch s := r.(type) {
-			case []interface{}:
-				r = implode(s)
-			case int:
-				r = implode([]interface{}{s})
-			case nil:
-				r = ""
-			case error:
-			default:
-				panic(r)
-			}
-		}()
-	}
+func funcSlice(_, v, e, s interface{}) (r interface{}) {
 	switch v := v.(type) {
 	case nil:
 		return nil
 	case []interface{}:
-		if start != nil {
-			if start, ok := toInt(start); ok {
-				if end != nil {
-					if end, ok := toInt(end); ok {
-						return funcIndexSlice(&start, &end, nil, v)
-					}
-					return &arrayIndexNotNumberError{end}
-				}
-				return funcIndexSlice(&start, nil, nil, v)
-			}
-			return &arrayIndexNotNumberError{start}
-		}
-		if end != nil {
-			if end, ok := toInt(end); ok {
-				return funcIndexSlice(nil, &end, nil, v)
-			}
-			return &arrayIndexNotNumberError{end}
+		return slice(v, e, s)
+	case string:
+		switch v := slice(explode(v), e, s).(type) {
+		case []interface{}:
+			return implode(v)
+		default:
+			return v
 		}
-		return v
 	default:
 		return &expectedArrayError{v}
 	}
 }
 
-func funcIndexSlice(start, end, index *int, a []interface{}) interface{} {
-	aa := a
-	if index != nil {
-		i := toIndex(aa, *index)
-		if i < 0 {
-			return nil
-		}
-		return a[i]
-	}
-	if end != nil {
-		i := toIndex(aa, *end)
-		if i == -1 {
-			i = len(a)
-		} else if i == -2 {
-			i = 0
+func slice(vs []interface{}, e, s interface{}) interface{} {
+	var start, end int
+	if s != nil {
+		if i, ok := toInt(s); ok {
+			start = clampIndex(i, 0, len(vs))
+		} else {
+			return &arrayIndexNotNumberError{s}
 		}
-		a = a[:i]
 	}
-	if start != nil {
-		i := toIndex(aa, *start)
-		if i == -1 || len(a) < i {
-			i = len(a)
-		} else if i == -2 {
-			i = 0
+	if e != nil {
+		if i, ok := toInt(e); ok {
+			end = clampIndex(i, start, len(vs))
+		} else {
+			return &arrayIndexNotNumberError{e}
 		}
-		a = a[i:]
+	} else {
+		end = len(vs)
 	}
-	return a
+	return vs[start:end]
 }
 
-func toIndex(a []interface{}, i int) int {
-	l := len(a)
-	switch {
-	case i < -l:
-		return -2
-	case i < 0:
-		return l + i
-	case i < l:
+func clampIndex(i, min, max int) int {
+	if i < 0 {
+		i += max
+	}
+	if i < min {
+		return min
+	} else if i < max {
 		return i
-	default:
-		return -1
+	} else {
+		return max
 	}
 }
 
-func funcIndices(v, x interface{}) interface{} {
-	return indexFunc(v, x, indices)
-}
-
-func funcLindex(v, x interface{}) interface{} {
-	return indexFunc(v, x, func(vs, xs []interface{}) interface{} {
-		if len(xs) == 0 {
-			return nil
-		}
-		for i := 0; i < len(vs) && i < len(vs)-len(xs)+1; i++ {
-			var neq bool
-			for j, y := range xs {
-				if neq = compare(vs[i+j], y) != 0; neq {
-					break
-				}
-			}
-			if !neq {
-				return i
-			}
-		}
-		return nil
-	})
-}
-
-func funcRindex(v, x interface{}) interface{} {
-	return indexFunc(v, x, func(vs, xs []interface{}) interface{} {
-		if len(xs) == 0 {
-			return nil
-		}
-		i := len(vs) - 1
-		if j := len(vs) - len(xs); j < i {
-			i = j
+func funcFlatten(v interface{}, args []interface{}) interface{} {
+	vs, ok := values(v)
+	if !ok {
+		return &funcTypeError{"flatten", v}
+	}
+	var depth float64
+	if len(args) == 0 {
+		depth = -1
+	} else {
+		depth, ok = toFloat(args[0])
+		if !ok {
+			return &funcTypeError{"flatten", args[0]}
 		}
-		for ; i >= 0; i-- {
-			var neq bool
-			for j, y := range xs {
-				if neq = compare(vs[i+j], y) != 0; neq {
-					break
-				}
-			}
-			if !neq {
-				return i
-			}
+		if depth < 0 {
+			return &flattenDepthError{depth}
 		}
-		return nil
-	})
+	}
+	return flatten(nil, vs, depth)
 }
 
-func indexFunc(v, x interface{}, f func(_, _ []interface{}) interface{}) interface{} {
-	switch v := v.(type) {
-	case nil:
-		return nil
-	case []interface{}:
-		switch x := x.(type) {
-		case []interface{}:
-			return f(v, x)
-		default:
-			return f(v, []interface{}{x})
-		}
-	case string:
-		if x, ok := x.(string); ok {
-			return f(explode(v), explode(x))
+func flatten(xs, vs []interface{}, depth float64) []interface{} {
+	for _, v := range vs {
+		if vs, ok := v.([]interface{}); ok && depth != 0 {
+			xs = flatten(xs, vs, depth-1)
+		} else {
+			xs = append(xs, v)
 		}
-		return &expectedStringError{x}
-	default:
-		return &expectedArrayError{v}
 	}
+	return xs
 }
 
 type rangeIter struct {
@@ -982,43 +1098,59 @@ func funcRange(_ interface{}, xs []interface{}) interface{} {
 	return &rangeIter{xs[0], xs[1], xs[2]}
 }
 
+func funcMin(v interface{}) interface{} {
+	vs, ok := v.([]interface{})
+	if !ok {
+		return &funcTypeError{"min", v}
+	}
+	return minMaxBy(vs, vs, true)
+}
+
 func funcMinBy(v, x interface{}) interface{} {
 	vs, ok := v.([]interface{})
 	if !ok {
-		return &expectedArrayError{v}
+		return &funcTypeError{"min_by", v}
 	}
 	xs, ok := x.([]interface{})
 	if !ok {
-		return &expectedArrayError{x}
+		return &funcTypeError{"min_by", x}
 	}
 	if len(vs) != len(xs) {
 		return &lengthMismatchError{"min_by", vs, xs}
 	}
-	return funcMinMaxBy(vs, xs, true)
+	return minMaxBy(vs, xs, true)
+}
+
+func funcMax(v interface{}) interface{} {
+	vs, ok := v.([]interface{})
+	if !ok {
+		return &funcTypeError{"max", v}
+	}
+	return minMaxBy(vs, vs, false)
 }
 
 func funcMaxBy(v, x interface{}) interface{} {
 	vs, ok := v.([]interface{})
 	if !ok {
-		return &expectedArrayError{v}
+		return &funcTypeError{"max_by", v}
 	}
 	xs, ok := x.([]interface{})
 	if !ok {
-		return &expectedArrayError{x}
+		return &funcTypeError{"max_by", x}
 	}
 	if len(vs) != len(xs) {
 		return &lengthMismatchError{"max_by", vs, xs}
 	}
-	return funcMinMaxBy(vs, xs, false)
+	return minMaxBy(vs, xs, false)
 }
 
-func funcMinMaxBy(vs, xs []interface{}, isMin bool) interface{} {
+func minMaxBy(vs, xs []interface{}, isMin bool) interface{} {
 	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 {
+		if compare(x, xs[i]) > 0 == isMin {
 			j, x = i, xs[i]
 		}
 	}
@@ -1029,8 +1161,38 @@ type sortItem struct {
 	value, key interface{}
 }
 
+func sortItems(name string, v, x interface{}) ([]*sortItem, error) {
+	vs, ok := v.([]interface{})
+	if !ok {
+		return nil, &funcTypeError{name, v}
+	}
+	xs, ok := x.([]interface{})
+	if !ok {
+		return nil, &funcTypeError{name, x}
+	}
+	if len(vs) != len(xs) {
+		return nil, &lengthMismatchError{name, vs, xs}
+	}
+	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 interface{}) interface{} {
+	return sortBy("sort", v, v)
+}
+
 func funcSortBy(v, x interface{}) interface{} {
-	items, err := sortItems("sort_by", v, x)
+	return sortBy("sort_by", v, x)
+}
+
+func sortBy(name string, v, x interface{}) interface{} {
+	items, err := sortItems(name, v, x)
 	if err != nil {
 		return err
 	}
@@ -1058,8 +1220,16 @@ func funcGroupBy(v, x interface{}) interface{} {
 	return rs
 }
 
+func funcUnique(v interface{}) interface{} {
+	return uniqueBy("unique", v, v)
+}
+
 func funcUniqueBy(v, x interface{}) interface{} {
-	items, err := sortItems("unique_by", v, x)
+	return uniqueBy("unique_by", v, x)
+}
+
+func uniqueBy(name string, v, x interface{}) interface{} {
+	items, err := sortItems(name, v, x)
 	if err != nil {
 		return err
 	}
@@ -1074,9 +1244,9 @@ func funcUniqueBy(v, x interface{}) interface{} {
 }
 
 func funcJoin(v, x interface{}) interface{} {
-	vs, ok := v.([]interface{})
+	vs, ok := values(v)
 	if !ok {
-		return &expectedArrayError{v}
+		return &funcTypeError{"join", v}
 	}
 	if len(vs) == 0 {
 		return ""
@@ -1086,48 +1256,26 @@ func funcJoin(v, x interface{}) interface{} {
 		return &funcTypeError{"join", x}
 	}
 	ss := make([]string, len(vs))
-	for i, e := range vs {
-		switch e := e.(type) {
+	for i, v := range vs {
+		switch v := v.(type) {
 		case nil:
 		case string:
-			ss[i] = e
+			ss[i] = v
 		case bool:
-			if e {
+			if v {
 				ss[i] = "true"
 			} else {
 				ss[i] = "false"
 			}
 		case int, float64, *big.Int:
-			ss[i] = jsonMarshal(e)
+			ss[i] = jsonMarshal(v)
 		default:
-			return &unaryTypeError{"join", e}
+			return &joinTypeError{v}
 		}
 	}
 	return strings.Join(ss, sep)
 }
 
-func sortItems(name string, v, x interface{}) ([]*sortItem, error) {
-	vs, ok := v.([]interface{})
-	if !ok {
-		return nil, &expectedArrayError{v}
-	}
-	xs, ok := x.([]interface{})
-	if !ok {
-		return nil, &expectedArrayError{x}
-	}
-	if len(vs) != len(xs) {
-		return nil, &lengthMismatchError{name, vs, xs}
-	}
-	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 funcSignificand(v float64) float64 {
 	if math.IsNaN(v) || math.IsInf(v, 0) || v == 0.0 {
 		return v
@@ -1309,7 +1457,7 @@ func updatePaths(v interface{}, path []interface{}, w interface{}, delpaths bool
 				if delpaths {
 					return v, nil
 				}
-				if y > 0x3ffffff {
+				if y >= 0x8000000 {
 					return nil, &arrayIndexTooLargeError{y}
 				}
 				l = y + 1
@@ -1356,30 +1504,16 @@ func updatePaths(v interface{}, path []interface{}, w interface{}, delpaths bool
 		switch uu := v.(type) {
 		case []interface{}:
 			var start, end int
-			if x, ok := toInt(x["start"]); ok {
-				x := toIndex(uu, x)
-				if x > len(uu) || x == -1 {
-					start = len(uu)
-				} else if x == -2 {
-					start = 0
-				} else {
-					start = x
-				}
+			if i, ok := toInt(x["start"]); ok {
+				start = clampIndex(i, 0, len(uu))
 			}
-			if x, ok := toInt(x["end"]); ok {
-				x := toIndex(uu, x)
-				if x == -1 {
-					end = len(uu)
-				} else if x < start {
-					end = start
-				} else {
-					end = x
-				}
+			if i, ok := toInt(x["end"]); ok {
+				end = clampIndex(i, start, len(uu))
 			} else {
 				end = len(uu)
 			}
 			if delpaths {
-				if start >= end {
+				if start == end {
 					return uu, nil
 				}
 				if len(path) > 1 {
@@ -1444,13 +1578,11 @@ func funcGetpath(v, p interface{}) interface{} {
 	u := v
 	for _, x := range keys {
 		switch v.(type) {
-		case map[string]interface{}:
-		case []interface{}:
-		case nil:
+		case nil, map[string]interface{}, []interface{}:
 		default:
 			return &getpathError{u, p}
 		}
-		v = funcIndex(nil, v, x)
+		v = funcIndex2(nil, v, x)
 		if _, ok := v.(error); ok {
 			return &getpathError{u, p}
 		}
@@ -1539,7 +1671,7 @@ func funcMktime(v interface{}) interface{} {
 		if err != nil {
 			return err
 		}
-		return float64(t.Unix())
+		return float64(t.Unix()) + float64(t.Nanosecond())/1e9
 	}
 	return &funcTypeError{"mktime", v}
 }
@@ -1728,6 +1860,27 @@ func compileRegexp(re, flags string) (*regexp.Regexp, error) {
 	return r, nil
 }
 
+func funcCapture(v interface{}) interface{} {
+	vs, ok := v.(map[string]interface{})
+	if !ok {
+		return &expectedObjectError{v}
+	}
+	v = vs["captures"]
+	captures, ok := v.([]interface{})
+	if !ok {
+		return &expectedArrayError{v}
+	}
+	w := make(map[string]interface{}, len(captures))
+	for _, capture := range captures {
+		if capture, ok := capture.(map[string]interface{}); ok {
+			if name, ok := capture["name"].(string); ok {
+				w[name] = capture["string"]
+			}
+		}
+	}
+	return w
+}
+
 func funcError(v interface{}, args []interface{}) interface{} {
 	if len(args) > 0 {
 		v = args[0]
@@ -1754,13 +1907,6 @@ func funcHaltError(v interface{}, args []interface{}) interface{} {
 	return &exitCodeError{v, code, true}
 }
 
-func internalfuncTypeError(v, x interface{}) interface{} {
-	if x, ok := x.(string); ok {
-		return &funcTypeError{x, v}
-	}
-	return &funcTypeError{"_type_error", v}
-}
-
 func toInt(x interface{}) (int, bool) {
 	switch x := x.(type) {
 	case int:
diff --git a/lexer.go b/lexer.go
index d36a683..a35322d 100644
--- a/lexer.go
+++ b/lexer.go
@@ -1,8 +1,7 @@
 package gojq
 
 import (
-	"strconv"
-	"strings"
+	"encoding/json"
 	"unicode/utf8"
 )
 
@@ -237,7 +236,6 @@ func (l *lexer) Lex(lval *yySymType) (tokenType int) {
 		if ch >= utf8.RuneSelf {
 			r, _ := utf8.DecodeRuneInString(l.source[l.offset-1:])
 			l.token = string(r)
-			l.offset += len(l.token)
 		}
 	}
 	return int(ch)
@@ -381,82 +379,129 @@ func (l *lexer) validNumber() bool {
 }
 
 func (l *lexer) scanString(start int) (int, string) {
-	var quote, newline bool
+	var decode bool
+	var controls int
 	unquote := func(src string, quote bool) (string, error) {
-		if quote {
-			src = "\"" + src + "\""
+		if !decode {
+			if quote {
+				return src, nil
+			}
+			return src[1 : len(src)-1], nil
 		}
-		if newline {
-			src = strings.ReplaceAll(src, "\n", "\\n")
+		var buf []byte
+		if !quote && controls == 0 {
+			buf = []byte(src)
+		} else {
+			buf = quoteAndEscape(src, quote, controls)
 		}
-		return strconv.Unquote(src)
+		if err := json.Unmarshal(buf, &src); err != nil {
+			return "", err
+		}
+		return src, nil
 	}
-	for i, m := l.offset, len(l.source); i < m; i++ {
+	for i := l.offset; i < len(l.source); i++ {
 		ch := l.source[i]
 		switch ch {
 		case '\\':
-			quote = !quote
-		case '\n':
-			newline = true
-		case '"':
-			if !quote {
-				if !l.inString {
-					l.offset = i + 1
-					l.token = l.source[start:l.offset]
-					str, err := unquote(l.token, false)
-					if err != nil {
-						return tokInvalid, ""
+			if i++; i >= len(l.source) {
+				break
+			}
+			switch l.source[i] {
+			case 'u':
+				for j := 1; j <= 4; j++ {
+					if i+j >= len(l.source) || !isHex(l.source[i+j]) {
+						l.offset = i + j
+						l.token = l.source[i-1 : l.offset]
+						return tokInvalidEscape, ""
 					}
-					return tokString, str
 				}
-				if i > l.offset {
-					l.offset = i
-					l.token = l.source[start:l.offset]
-					str, err := unquote(l.token, true)
-					if err != nil {
-						return tokInvalid, ""
-					}
-					return tokString, str
+				i += 4
+				fallthrough
+			case '"', '/', '\\', 'b', 'f', 'n', 'r', 't':
+				decode = true
+			case '(':
+				if !l.inString {
+					l.inString = true
+					return tokStringStart, ""
 				}
-				l.inString = false
-				l.offset = i + 1
-				return tokStringEnd, ""
-			}
-			quote = false
-		case '(':
-			if quote {
-				if l.inString {
-					if i > l.offset+1 {
-						l.offset = i - 1
-						l.token = l.source[start:l.offset]
-						str, err := unquote(l.token, true)
-						if err != nil {
-							return tokInvalid, ""
-						}
-						return tokString, str
-					}
-					l.offset = i + 1
+				if i == l.offset+1 {
+					l.offset += 2
 					l.inString = false
 					return tokStringQuery, ""
 				}
-				l.inString = true
-				return tokStringStart, ""
+				l.offset = i - 1
+				l.token = l.source[start:l.offset]
+				str, err := unquote(l.token, true)
+				if err != nil {
+					return tokInvalid, ""
+				}
+				return tokString, str
+			default:
+				l.offset = i + 1
+				l.token = l.source[l.offset-2 : l.offset]
+				return tokInvalidEscape, ""
 			}
-		default:
-			if quote {
-				if !('a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' ||
-					'0' <= ch && ch <= '9' || ch == '\'' || ch == '"') {
-					l.offset = i + 1
-					l.token = l.source[l.offset-2 : l.offset]
+		case '"':
+			if !l.inString {
+				l.offset = i + 1
+				l.token = l.source[start:l.offset]
+				str, err := unquote(l.token, false)
+				if err != nil {
 					return tokInvalid, ""
 				}
-				quote = false
+				return tokString, str
+			}
+			if i > l.offset {
+				l.offset = i
+				l.token = l.source[start:l.offset]
+				str, err := unquote(l.token, true)
+				if err != nil {
+					return tokInvalid, ""
+				}
+				return tokString, str
+			}
+			l.inString = false
+			l.offset = i + 1
+			return tokStringEnd, ""
+		default:
+			if !decode {
+				decode = ch > '~'
+			}
+			if ch < ' ' { // ref: unquoteBytes in encoding/json
+				controls++
 			}
 		}
 	}
 	l.offset = len(l.source)
 	l.token = l.source[start:l.offset]
-	return tokInvalid, ""
+	return tokUnterminatedString, ""
+}
+
+func quoteAndEscape(src string, quote bool, controls int) []byte {
+	size := len(src) + controls*5
+	if quote {
+		size += 2
+	}
+	buf := make([]byte, size)
+	var j int
+	if quote {
+		buf[0] = '"'
+		buf[len(buf)-1] = '"'
+		j++
+	}
+	for i := 0; i < len(src); i++ {
+		if ch := src[i]; ch < ' ' {
+			const hex = "0123456789abcdef"
+			copy(buf[j:], `\u00`)
+			buf[j+4] = hex[ch>>4]
+			buf[j+5] = hex[ch&0xF]
+			j += 6
+		} else {
+			buf[j] = ch
+			j++
+		}
+	}
+	return buf
 }
 
 type parseError struct {
@@ -466,24 +511,24 @@ type parseError struct {
 }
 
 func (err *parseError) Error() string {
-	var message string
-	prefix := "unexpected"
-	switch {
-	case err.tokenType == eof:
-		message = "<EOF>"
-	case err.tokenType == tokInvalid:
-		prefix = "invalid"
-		fallthrough
-	case err.tokenType >= utf8.RuneSelf:
-		if strings.HasPrefix(err.token, "\"") {
-			message = err.token
+	switch err.tokenType {
+	case eof:
+		return "unexpected token <EOF>"
+	case tokInvalid:
+		return "invalid token " + jsonMarshal(err.token)
+	case tokInvalidEscape:
+		return `invalid escape sequence "` + err.token + `" in string literal`
+	case tokUnterminatedString:
+		return "unterminated string literal"
+	default:
+		var message string
+		if err.tokenType >= utf8.RuneSelf {
+			message = jsonMarshal(err.token)
 		} else {
-			message = "\"" + err.token + "\""
+			message = jsonMarshal(string(rune(err.tokenType)))
 		}
-	default:
-		message = strconv.Quote(string(rune(err.tokenType)))
+		return "unexpected token " + message
 	}
-	return prefix + " token " + message
 }
 
 func (err *parseError) Token() (string, int) {
@@ -493,10 +538,11 @@ func (err *parseError) Token() (string, int) {
 func (l *lexer) Error(string) {
 	offset, token := l.offset, l.token
 	switch {
-	case l.tokenType == eof:
+	case l.tokenType == eof || l.tokenType == tokUnterminatedString:
 		offset++
-	case l.tokenType >= utf8.RuneSelf:
+	case l.tokenType > 0xFF:
 		offset -= len(token) - 1
+	case l.tokenType >= utf8.RuneSelf:
 	default:
 		token = string(rune(l.tokenType))
 	}
@@ -518,6 +564,12 @@ func isIdent(ch byte, tail bool) bool {
 		tail && isNumber(ch)
 }
 
+func isHex(ch byte) bool {
+	return 'a' <= ch && ch <= 'f' ||
+		'A' <= ch && ch <= 'F' ||
+		isNumber(ch)
+}
+
 func isNumber(ch byte) bool {
 	return '0' <= ch && ch <= '9'
 }
diff --git a/math.go b/math.go
index 55d6476..c315f72 100644
--- a/math.go
+++ b/math.go
@@ -3,8 +3,6 @@ package gojq
 import "math/bits"
 
 const (
-	maxInt     = 1<<(bits.UintSize-1) - 1   // math.MaxInt64 or math.MaxInt32
-	minInt     = -maxInt - 1                // math.MinInt64 or math.MinInt32
-	maxHalfInt = 1<<(bits.UintSize/2-1) - 1 // math.MaxInt32 or math.MaxInt16
-	minHalfInt = -maxHalfInt - 1            // math.MinInt32 or math.MinInt16
+	maxInt = 1<<(bits.UintSize-1) - 1 // math.MaxInt64 or math.MaxInt32
+	minInt = -maxInt - 1              // math.MinInt64 or math.MinInt32
 )
diff --git a/operator.go b/operator.go
index 80e13ef..a03d021 100644
--- a/operator.go
+++ b/operator.go
@@ -220,11 +220,7 @@ func binopTypeSwitch(
 	case int:
 		switch r := r.(type) {
 		case int:
-			if minHalfInt <= l && l <= maxHalfInt &&
-				minHalfInt <= r && r <= maxHalfInt {
-				return callbackInts(l, r)
-			}
-			return callbackBigInts(big.NewInt(int64(l)), big.NewInt(int64(r)))
+			return callbackInts(l, r)
 		case float64:
 			return callbackFloats(float64(l), r)
 		case *big.Int:
@@ -307,26 +303,36 @@ func funcOpNegate(v interface{}) interface{} {
 }
 
 func funcOpAdd(_, l, r interface{}) interface{} {
-	if l == nil {
-		return r
-	} else if r == nil {
-		return l
-	}
 	return binopTypeSwitch(l, r,
-		func(l, r int) interface{} { return l + r },
+		func(l, r int) interface{} {
+			if v := l + r; (v >= l) == (r >= 0) {
+				return v
+			}
+			x, y := big.NewInt(int64(l)), big.NewInt(int64(r))
+			return x.Add(x, y)
+		},
 		func(l, r float64) interface{} { return l + r },
 		func(l, r *big.Int) interface{} { return new(big.Int).Add(l, r) },
 		func(l, r string) interface{} { return l + r },
 		func(l, r []interface{}) interface{} {
+			if len(l) == 0 {
+				return r
+			}
 			if len(r) == 0 {
 				return l
-			} else if len(l) == 0 {
-				return r
 			}
-			v := make([]interface{}, 0, len(l)+len(r))
-			return append(append(v, l...), r...)
+			v := make([]interface{}, len(l)+len(r))
+			copy(v, l)
+			copy(v[len(l):], r)
+			return v
 		},
 		func(l, r map[string]interface{}) interface{} {
+			if len(l) == 0 {
+				return r
+			}
+			if len(r) == 0 {
+				return l
+			}
 			m := make(map[string]interface{}, len(l)+len(r))
 			for k, v := range l {
 				m[k] = v
@@ -336,31 +342,42 @@ func funcOpAdd(_, l, r interface{}) interface{} {
 			}
 			return m
 		},
-		func(l, r interface{}) interface{} { return &binopTypeError{"add", l, r} },
+		func(l, r interface{}) interface{} {
+			if l == nil {
+				return r
+			}
+			if r == nil {
+				return l
+			}
+			return &binopTypeError{"add", l, r}
+		},
 	)
 }
 
 func funcOpSub(_, l, r interface{}) interface{} {
 	return binopTypeSwitch(l, r,
-		func(l, r int) interface{} { return l - r },
+		func(l, r int) interface{} {
+			if v := l - r; (v <= l) == (r >= 0) {
+				return v
+			}
+			x, y := big.NewInt(int64(l)), big.NewInt(int64(r))
+			return x.Sub(x, y)
+		},
 		func(l, r float64) interface{} { return l - r },
 		func(l, r *big.Int) interface{} { return new(big.Int).Sub(l, r) },
 		func(l, r string) interface{} { return &binopTypeError{"subtract", l, r} },
 		func(l, r []interface{}) interface{} {
-			a := make([]interface{}, 0, len(l))
-			for _, v := range l {
-				var found bool
-				for _, w := range r {
-					if compare(v, w) == 0 {
-						found = true
-						break
+			v := make([]interface{}, 0, len(l))
+		L:
+			for _, l := range l {
+				for _, r := range r {
+					if compare(l, r) == 0 {
+						continue L
 					}
 				}
-				if !found {
-					a = append(a, v)
-				}
+				v = append(v, l)
 			}
-			return a
+			return v
 		},
 		func(l, r map[string]interface{}) interface{} { return &binopTypeError{"subtract", l, r} },
 		func(l, r interface{}) interface{} { return &binopTypeError{"subtract", l, r} },
@@ -369,7 +386,13 @@ func funcOpSub(_, l, r interface{}) interface{} {
 
 func funcOpMul(_, l, r interface{}) interface{} {
 	return binopTypeSwitch(l, r,
-		func(l, r int) interface{} { return l * r },
+		func(l, r int) interface{} {
+			if v := l * r; r == 0 || v/r == l {
+				return v
+			}
+			x, y := big.NewInt(int64(l)), big.NewInt(int64(r))
+			return x.Mul(x, y)
+		},
 		func(l, r float64) interface{} { return l * r },
 		func(l, r *big.Int) interface{} { return new(big.Int).Mul(l, r) },
 		func(l, r string) interface{} { return &binopTypeError{"multiply", l, r} },
@@ -377,7 +400,7 @@ func funcOpMul(_, l, r interface{}) interface{} {
 		deepMergeObjects,
 		func(l, r interface{}) interface{} {
 			multiplyString := func(s string, cnt float64) interface{} {
-				if cnt <= 0.0 || cnt > float64(maxHalfInt/(16*(len(s)+1))) || math.IsNaN(cnt) {
+				if cnt <= 0.0 || len(s) > 0 && cnt > float64(0x10000000/len(s)) || math.IsNaN(cnt) {
 					return nil
 				}
 				if cnt < 1.0 {
diff --git a/option_test.go b/option_test.go
index 4440b11..1c4c8b8 100644
--- a/option_test.go
+++ b/option_test.go
@@ -4,7 +4,6 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
-	"math/big"
 	"reflect"
 	"testing"
 
@@ -37,9 +36,12 @@ func TestWithModuleLoaderError(t *testing.T) {
 	if !ok {
 		t.Fatal("should emit an error but got no output")
 	}
-	err, expected := v.(error), `cannot load module: "m"`
-	if got := err.Error(); got != expected {
-		t.Errorf("expected: %v, got: %v", expected, got)
+	if err, ok := v.(error); ok {
+		if expected := `cannot load module: "m"`; err.Error() != expected {
+			t.Errorf("expected: %v, got: %v", expected, err)
+		}
+	} else {
+		t.Errorf("should emit an error but got: %v", v)
 	}
 	v, ok = iter.Next()
 	if ok {
@@ -96,7 +98,7 @@ func (*moduleLoaderJSON) LoadJSON(name string) (interface{}, error) {
 func TestWithModuleLoader_JSON(t *testing.T) {
 	query, err := gojq.Parse(`
 		import "module1" as $m;
-		[$m, $m[1]*$m[2]*1000000000000]
+		[$m, $m[1]*$m[2]]
 	`)
 	if err != nil {
 		t.Fatal(err)
@@ -114,10 +116,7 @@ func TestWithModuleLoader_JSON(t *testing.T) {
 		if !ok {
 			break
 		}
-		if expected := []interface{}{
-			[]interface{}{1.0, 42, 123},
-			big.NewInt(5166000000000000),
-		}; !reflect.DeepEqual(got, expected) {
+		if expected := []interface{}{[]interface{}{1.0, 42, 123}, 5166}; !reflect.DeepEqual(got, expected) {
 			t.Errorf("expected: %v, got: %v", expected, got)
 		}
 	}
@@ -182,7 +181,7 @@ func TestWithEnvironLoader(t *testing.T) {
 		}
 		expected := map[string]interface{}{"foo": "42", "bar": "128", "qux": ""}
 		if !reflect.DeepEqual(got, expected) {
-			t.Errorf("expected: %#v, got: %#v", expected, got)
+			t.Errorf("expected: %v, got: %v", expected, got)
 		}
 	}
 }
@@ -244,9 +243,12 @@ func TestWithVariablesError1(t *testing.T) {
 	if !ok {
 		t.Fatal("should emit an error but got no output")
 	}
-	err, expected := v.(error), "variable defined but not bound: $x"
-	if got := err.Error(); got != expected {
-		t.Errorf("expected: %v, got: %v", expected, got)
+	if err, ok := v.(error); ok {
+		if expected := "variable defined but not bound: $x"; err.Error() != expected {
+			t.Errorf("expected: %v, got: %v", expected, err)
+		}
+	} else {
+		t.Errorf("should emit an error but got: %v", v)
 	}
 	v, ok = iter.Next()
 	if ok {
@@ -271,9 +273,12 @@ func TestWithVariablesError2(t *testing.T) {
 	if !ok {
 		t.Fatal("should emit an error but got no output")
 	}
-	err, expected := v.(error), "too many variable values provided"
-	if got := err.Error(); got != expected {
-		t.Errorf("expected: %v, got: %v", expected, got)
+	if err, ok := v.(error); ok {
+		if expected := "too many variable values provided"; err.Error() != expected {
+			t.Errorf("expected: %v, got: %v", expected, err)
+		}
+	} else {
+		t.Errorf("should emit an error but got: %v", v)
 	}
 	v, ok = iter.Next()
 	if ok {
@@ -543,7 +548,7 @@ func TestWithFunctionValueError(t *testing.T) {
 			break
 		}
 		if !reflect.DeepEqual(v, expected) {
-			t.Errorf("expected: %#v, got: %#v", expected, v)
+			t.Errorf("expected: %v, got: %v", expected, v)
 		}
 	}
 }
@@ -710,9 +715,12 @@ func TestWithIterFunctionPathError(t *testing.T) {
 	if !ok {
 		t.Fatal("should emit an error but got no output")
 	}
-	err, expected := v.(error), "invalid path on iterating against: gojq.Iter"
-	if got := err.Error(); got != expected {
-		t.Errorf("expected: %v, got: %v", expected, got)
+	if err, ok := v.(error); ok {
+		if expected := "invalid path on iterating against: gojq.Iter"; err.Error() != expected {
+			t.Errorf("expected: %v, got: %v", expected, err)
+		}
+	} else {
+		t.Errorf("should emit an error but got: %v", v)
 	}
 }
 
diff --git a/parser.go b/parser.go
index 452c8d1..b996fe2 100644
--- a/parser.go
+++ b/parser.go
@@ -61,24 +61,26 @@ const tokModuleVariable = 57365
 const tokIndex = 57366
 const tokNumber = 57367
 const tokFormat = 57368
-const tokInvalid = 57369
-const tokString = 57370
-const tokStringStart = 57371
-const tokStringQuery = 57372
-const tokStringEnd = 57373
-const tokIf = 57374
-const tokThen = 57375
-const tokElif = 57376
-const tokElse = 57377
-const tokEnd = 57378
-const tokTry = 57379
-const tokCatch = 57380
-const tokReduce = 57381
-const tokForeach = 57382
-const tokRecurse = 57383
-const tokFuncDefPost = 57384
-const tokTermPost = 57385
-const tokEmptyCatch = 57386
+const tokString = 57369
+const tokStringStart = 57370
+const tokStringQuery = 57371
+const tokStringEnd = 57372
+const tokIf = 57373
+const tokThen = 57374
+const tokElif = 57375
+const tokElse = 57376
+const tokEnd = 57377
+const tokTry = 57378
+const tokCatch = 57379
+const tokReduce = 57380
+const tokForeach = 57381
+const tokRecurse = 57382
+const tokFuncDefPost = 57383
+const tokTermPost = 57384
+const tokEmptyCatch = 57385
+const tokInvalid = 57386
+const tokInvalidEscape = 57387
+const tokUnterminatedString = 57388
 
 var yyToknames = [...]string{
 	"$end",
@@ -107,7 +109,6 @@ var yyToknames = [...]string{
 	"tokIndex",
 	"tokNumber",
 	"tokFormat",
-	"tokInvalid",
 	"tokString",
 	"tokStringStart",
 	"tokStringQuery",
@@ -125,6 +126,9 @@ var yyToknames = [...]string{
 	"tokFuncDefPost",
 	"tokTermPost",
 	"tokEmptyCatch",
+	"tokInvalid",
+	"tokInvalidEscape",
+	"tokUnterminatedString",
 	"'|'",
 	"','",
 	"'+'",
@@ -150,7 +154,7 @@ const yyEofCode = 1
 const yyErrCode = 2
 const yyInitialStackSize = 16
 
-//line parser.go.y:687
+//line parser.go.y:688
 
 //line yacctab:1
 var yyExca = [...]int{
@@ -158,7 +162,7 @@ var yyExca = [...]int{
 	1, -1,
 	-2, 0,
 	-1, 97,
-	53, 0,
+	55, 0,
 	-2, 104,
 	-1, 130,
 	5, 0,
@@ -167,164 +171,167 @@ var yyExca = [...]int{
 	9, 0,
 	-2, 35,
 	-1, 194,
-	56, 114,
+	58, 114,
 	-2, 54,
 }
 
 const yyPrivate = 57344
 
-const yyLast = 1094
+const yyLast = 1127
 
 var yyAct = [...]int{
 	86, 214, 174, 112, 12, 203, 9, 175, 111, 31,
 	190, 6, 156, 140, 117, 47, 95, 97, 93, 94,
-	89, 227, 49, 75, 76, 7, 77, 78, 79, 240,
-	235, 103, 239, 106, 164, 123, 226, 119, 107, 108,
-	105, 234, 102, 75, 76, 113, 77, 78, 79, 163,
-	122, 104, 211, 75, 76, 210, 77, 78, 79, 158,
-	159, 264, 259, 243, 72, 74, 80, 81, 82, 83,
-	84, 229, 73, 127, 275, 128, 129, 130, 131, 132,
-	133, 134, 135, 136, 137, 138, 80, 81, 82, 83,
-	84, 228, 73, 147, 72, 74, 80, 81, 82, 83,
-	84, 145, 73, 141, 278, 161, 246, 277, 157, 225,
-	166, 165, 144, 126, 125, 167, 88, 42, 43, 245,
-	124, 258, 224, 206, 179, 180, 181, 44, 183, 184,
-	73, 242, 177, 154, 153, 178, 142, 186, 49, 173,
-	267, 100, 143, 92, 91, 90, 92, 191, 99, 197,
-	150, 120, 200, 192, 201, 202, 188, 256, 257, 207,
-	88, 182, 98, 198, 199, 209, 219, 7, 216, 101,
-	215, 215, 218, 213, 113, 155, 185, 75, 76, 3,
-	77, 78, 79, 42, 43, 221, 222, 28, 91, 90,
-	92, 179, 180, 181, 230, 204, 205, 232, 8, 177,
-	223, 27, 178, 80, 81, 82, 83, 84, 220, 73,
-	85, 157, 241, 176, 46, 149, 237, 110, 72, 74,
-	80, 81, 82, 83, 84, 88, 73, 152, 182, 196,
-	79, 191, 195, 255, 7, 253, 254, 192, 248, 247,
-	236, 160, 249, 250, 96, 262, 260, 261, 215, 263,
-	11, 121, 189, 91, 90, 92, 11, 268, 269, 187,
-	270, 82, 83, 84, 139, 73, 272, 273, 80, 81,
-	82, 83, 84, 208, 73, 279, 10, 5, 271, 280,
-	51, 52, 4, 53, 54, 55, 56, 57, 58, 59,
-	60, 61, 62, 115, 116, 170, 2, 171, 169, 1,
-	0, 42, 43, 0, 0, 63, 64, 65, 66, 67,
-	68, 69, 70, 71, 0, 0, 20, 0, 17, 37,
-	24, 25, 26, 38, 40, 39, 41, 23, 29, 30,
-	114, 42, 43, 0, 212, 15, 0, 0, 0, 0,
-	16, 0, 13, 14, 22, 0, 0, 0, 0, 0,
-	33, 34, 0, 0, 0, 21, 0, 36, 0, 148,
-	32, 0, 146, 35, 51, 52, 0, 53, 54, 55,
-	56, 57, 58, 59, 60, 61, 62, 115, 116, 0,
+	89, 141, 49, 7, 179, 180, 181, 240, 246, 264,
+	239, 103, 177, 106, 178, 227, 164, 119, 107, 108,
+	105, 245, 102, 75, 76, 113, 77, 78, 79, 123,
+	226, 163, 211, 225, 259, 210, 142, 179, 180, 181,
+	158, 159, 143, 182, 122, 177, 224, 178, 219, 7,
+	235, 234, 104, 127, 243, 128, 129, 130, 131, 132,
+	133, 134, 135, 136, 137, 138, 72, 74, 80, 81,
+	82, 83, 84, 147, 73, 88, 182, 196, 73, 229,
+	195, 145, 7, 150, 228, 161, 166, 165, 157, 126,
+	125, 124, 144, 88, 258, 167, 80, 81, 82, 83,
+	84, 206, 73, 44, 242, 91, 90, 92, 183, 184,
+	82, 83, 84, 154, 73, 153, 267, 186, 49, 173,
+	42, 43, 100, 91, 90, 92, 99, 191, 120, 197,
+	256, 257, 200, 192, 201, 202, 188, 75, 76, 207,
+	77, 78, 79, 198, 199, 209, 42, 43, 216, 92,
+	215, 215, 218, 213, 113, 98, 75, 76, 185, 77,
+	78, 79, 204, 205, 101, 221, 222, 170, 155, 171,
+	169, 3, 28, 27, 230, 96, 220, 232, 176, 46,
+	223, 11, 80, 81, 82, 83, 84, 11, 73, 78,
+	79, 157, 241, 110, 8, 152, 237, 255, 236, 72,
+	74, 80, 81, 82, 83, 84, 85, 73, 79, 278,
+	160, 191, 277, 121, 189, 253, 254, 192, 248, 247,
+	187, 139, 249, 250, 208, 262, 260, 261, 215, 263,
+	80, 81, 82, 83, 84, 149, 73, 268, 269, 10,
+	270, 5, 4, 2, 1, 88, 272, 273, 80, 81,
+	82, 83, 84, 0, 73, 279, 0, 0, 271, 280,
+	51, 52, 0, 53, 54, 55, 56, 57, 58, 59,
+	60, 61, 62, 115, 116, 91, 90, 92, 0, 0,
+	42, 43, 0, 87, 63, 64, 65, 66, 67, 68,
+	69, 70, 71, 88, 0, 20, 0, 17, 37, 24,
+	25, 26, 38, 40, 39, 41, 23, 29, 30, 42,
+	43, 0, 114, 15, 0, 0, 212, 0, 16, 0,
+	13, 14, 22, 91, 90, 92, 0, 0, 0, 0,
+	0, 33, 34, 0, 0, 0, 21, 0, 36, 0,
+	148, 32, 0, 146, 35, 51, 52, 0, 53, 54,
+	55, 56, 57, 58, 59, 60, 61, 62, 115, 116,
 	0, 0, 0, 0, 0, 42, 43, 0, 0, 63,
 	64, 65, 66, 67, 68, 69, 70, 71, 18, 19,
 	20, 0, 17, 37, 24, 25, 26, 38, 40, 39,
-	41, 23, 29, 30, 114, 42, 43, 0, 109, 15,
-	0, 0, 0, 0, 16, 0, 13, 14, 22, 0,
+	41, 23, 29, 30, 42, 43, 0, 114, 15, 0,
+	0, 109, 0, 16, 0, 13, 14, 22, 0, 0,
+	0, 0, 0, 0, 0, 0, 33, 34, 0, 0,
+	0, 21, 0, 36, 0, 0, 32, 0, 20, 35,
+	17, 37, 24, 25, 26, 38, 40, 39, 41, 23,
+	29, 30, 42, 43, 0, 0, 15, 0, 0, 0,
+	0, 16, 0, 13, 14, 22, 0, 0, 0, 0,
+	0, 0, 0, 0, 33, 34, 0, 0, 0, 21,
+	0, 36, 0, 0, 32, 0, 231, 35, 20, 0,
+	17, 37, 24, 25, 26, 38, 40, 39, 41, 23,
+	29, 30, 42, 43, 0, 0, 15, 0, 0, 0,
+	0, 16, 0, 13, 14, 22, 0, 0, 0, 0,
 	0, 0, 0, 0, 33, 34, 0, 0, 0, 21,
-	0, 36, 0, 0, 32, 0, 20, 35, 17, 37,
-	24, 25, 26, 38, 40, 39, 41, 23, 29, 30,
-	0, 42, 43, 0, 0, 15, 0, 0, 0, 0,
-	16, 0, 13, 14, 22, 0, 87, 0, 0, 0,
-	33, 34, 0, 0, 0, 21, 88, 36, 0, 0,
-	32, 0, 231, 35, 20, 0, 17, 37, 24, 25,
-	26, 38, 40, 39, 41, 23, 29, 30, 0, 42,
-	43, 0, 0, 15, 91, 90, 92, 0, 16, 0,
-	13, 14, 22, 0, 0, 0, 0, 0, 33, 34,
-	0, 0, 0, 21, 0, 36, 0, 0, 32, 0,
-	118, 35, 20, 0, 17, 37, 24, 25, 26, 38,
-	40, 39, 41, 23, 29, 30, 0, 42, 43, 0,
-	0, 15, 0, 77, 78, 79, 16, 0, 13, 14,
-	22, 0, 0, 0, 0, 0, 33, 34, 0, 0,
-	0, 21, 0, 36, 0, 0, 32, 51, 52, 35,
-	53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
-	48, 0, 0, 80, 81, 82, 83, 84, 50, 73,
-	0, 0, 63, 64, 65, 66, 67, 68, 69, 70,
+	0, 36, 0, 0, 32, 0, 118, 35, 20, 0,
+	17, 37, 24, 25, 26, 38, 40, 39, 41, 23,
+	29, 30, 42, 43, 0, 0, 15, 0, 77, 78,
+	79, 16, 0, 13, 14, 22, 0, 0, 0, 0,
+	0, 0, 0, 0, 33, 34, 0, 0, 0, 21,
+	0, 36, 0, 0, 32, 51, 52, 35, 53, 54,
+	55, 56, 57, 58, 59, 60, 61, 62, 48, 0,
+	80, 81, 82, 83, 84, 50, 73, 0, 0, 63,
+	64, 65, 66, 67, 68, 69, 70, 71, 51, 52,
+	0, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+	62, 48, 0, 0, 0, 0, 0, 0, 50, 0,
+	0, 172, 63, 64, 65, 66, 67, 68, 69, 70,
 	71, 51, 52, 0, 53, 54, 55, 56, 57, 58,
-	59, 60, 61, 62, 48, 0, 0, 0, 0, 0,
-	0, 172, 50, 0, 0, 0, 63, 64, 65, 66,
-	67, 68, 69, 70, 71, 51, 52, 0, 53, 54,
-	55, 56, 57, 58, 59, 60, 61, 62, 115, 194,
-	78, 79, 0, 0, 0, 45, 42, 43, 0, 0,
-	63, 64, 65, 66, 67, 68, 69, 70, 71, 37,
-	24, 25, 26, 38, 40, 39, 41, 23, 29, 30,
-	0, 42, 43, 75, 76, 193, 77, 78, 79, 80,
-	81, 82, 83, 84, 22, 73, 0, 0, 0, 0,
-	33, 34, 0, 0, 0, 21, 0, 36, 0, 0,
-	32, 75, 76, 35, 77, 78, 79, 0, 0, 0,
-	0, 0, 0, 0, 72, 74, 80, 81, 82, 83,
-	84, 0, 73, 0, 0, 0, 75, 76, 252, 77,
-	78, 79, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 72, 74, 80, 81, 82, 83, 84, 0,
-	73, 0, 0, 0, 75, 76, 233, 77, 78, 79,
-	0, 0, 0, 0, 0, 0, 0, 72, 74, 80,
-	81, 82, 83, 84, 0, 73, 0, 0, 0, 75,
-	76, 168, 77, 78, 79, 0, 0, 0, 0, 0,
+	59, 60, 61, 62, 115, 194, 0, 0, 0, 0,
+	0, 42, 43, 0, 45, 63, 64, 65, 66, 67,
+	68, 69, 70, 71, 37, 24, 25, 26, 38, 40,
+	39, 41, 23, 29, 30, 42, 43, 75, 76, 0,
+	77, 78, 79, 193, 0, 0, 0, 0, 22, 0,
+	0, 0, 0, 0, 0, 0, 0, 33, 34, 0,
+	0, 0, 21, 0, 36, 0, 0, 32, 75, 76,
+	35, 77, 78, 79, 0, 0, 0, 0, 0, 0,
+	72, 74, 80, 81, 82, 83, 84, 0, 73, 0,
+	0, 0, 75, 76, 252, 77, 78, 79, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 72, 74, 80, 81, 82, 83, 84, 0, 73,
+	0, 0, 0, 75, 76, 233, 77, 78, 79, 0,
 	0, 0, 0, 0, 0, 72, 74, 80, 81, 82,
-	83, 84, 0, 73, 0, 0, 75, 76, 281, 77,
-	78, 79, 0, 0, 0, 0, 0, 0, 0, 0,
+	83, 84, 0, 73, 0, 0, 0, 75, 76, 168,
+	77, 78, 79, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 72, 74, 80, 81,
+	82, 83, 84, 0, 73, 0, 0, 75, 76, 281,
+	77, 78, 79, 0, 0, 0, 0, 0, 0, 0,
 	72, 74, 80, 81, 82, 83, 84, 0, 73, 0,
 	0, 75, 76, 276, 77, 78, 79, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 72, 74, 80,
-	81, 82, 83, 84, 0, 73, 0, 0, 75, 76,
-	251, 77, 78, 79, 0, 0, 0, 0, 0, 0,
-	0, 0, 72, 74, 80, 81, 82, 83, 84, 0,
-	73, 0, 0, 75, 76, 244, 77, 78, 79, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 72,
-	74, 80, 81, 82, 83, 84, 0, 73, 0, 0,
-	75, 76, 217, 77, 78, 79, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	72, 74, 80, 81, 82, 83, 84, 0, 73, 0,
+	0, 75, 76, 251, 77, 78, 79, 0, 0, 0,
 	0, 0, 0, 0, 72, 74, 80, 81, 82, 83,
-	84, 0, 73, 0, 0, 75, 76, 162, 77, 78,
+	84, 0, 73, 0, 0, 75, 76, 244, 77, 78,
 	79, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 72, 74, 80, 81, 82, 83, 84, 0, 73,
-	0, 266, 75, 76, 0, 77, 78, 79, 0, 0,
-	0, 0, 0, 0, 0, 0, 72, 74, 80, 81,
-	82, 83, 84, 0, 73, 0, 265, 75, 76, 0,
-	77, 78, 79, 0, 0, 0, 75, 76, 0, 77,
-	78, 79, 0, 72, 74, 80, 81, 82, 83, 84,
-	0, 73, 0, 238, 75, 76, 274, 77, 78, 79,
-	0, 0, 0, 0, 0, 151, 0, 0, 72, 74,
-	80, 81, 82, 83, 84, 0, 73, 72, 74, 80,
-	81, 82, 83, 84, 0, 73, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 72, 74, 80, 81, 82,
-	83, 84, 0, 73,
+	0, 0, 0, 0, 72, 74, 80, 81, 82, 83,
+	84, 0, 73, 0, 0, 75, 76, 217, 77, 78,
+	79, 0, 0, 0, 0, 0, 0, 0, 72, 74,
+	80, 81, 82, 83, 84, 0, 73, 0, 0, 75,
+	76, 162, 77, 78, 79, 0, 0, 0, 0, 0,
+	75, 76, 0, 77, 78, 79, 0, 0, 72, 74,
+	80, 81, 82, 83, 84, 0, 73, 0, 275, 75,
+	76, 0, 77, 78, 79, 0, 0, 0, 0, 0,
+	0, 0, 72, 74, 80, 81, 82, 83, 84, 0,
+	73, 0, 266, 72, 74, 80, 81, 82, 83, 84,
+	0, 73, 0, 265, 75, 76, 0, 77, 78, 79,
+	0, 0, 72, 74, 80, 81, 82, 83, 84, 0,
+	73, 0, 238, 0, 0, 0, 75, 76, 0, 77,
+	78, 79, 274, 0, 0, 75, 76, 0, 77, 78,
+	79, 0, 0, 0, 0, 0, 0, 72, 74, 80,
+	81, 82, 83, 84, 151, 73, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 72,
+	74, 80, 81, 82, 83, 84, 0, 73, 72, 74,
+	80, 81, 82, 83, 84, 0, 73,
 }
 
 var yyPact = [...]int{
-	169, -1000, -1000, -35, -1000, 387, 72, 614, -1000, 1040,
-	-1000, 529, 462, 673, 673, 529, 529, 141, 120, 113,
-	149, 89, -1000, -1000, -1000, -1000, -1000, -6, -1000, -1000,
-	155, -1000, 529, 673, 673, 357, 481, 130, -1000, -1000,
-	-1000, -1000, -1000, -1000, -1000, -1000, -11, -1000, 64, 58,
-	57, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
+	181, -1000, -1000, -39, -1000, 387, 66, 621, -1000, 1071,
+	-1000, 535, 289, 678, 678, 535, 535, 154, 119, 115,
+	164, 113, -1000, -1000, -1000, -1000, -1000, 13, -1000, -1000,
+	139, -1000, 535, 678, 678, 358, 485, 127, -1000, -1000,
+	-1000, -1000, -1000, -1000, -1000, -1000, 1, -1000, 53, 52,
+	51, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
 	-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-	-1000, -1000, 529, -1000, 529, 529, 529, 529, 529, 529,
-	529, 529, 529, 529, 529, -1000, 1040, 82, -1000, -1000,
-	-1000, 89, 303, 201, 136, 1022, 529, 96, 88, 161,
-	-35, 3, -1000, -1000, 529, -1000, 909, 92, 92, -1000,
-	-12, -1000, 55, 54, 529, -1000, -1000, -1000, -1000, 752,
-	-1000, 267, -1000, 580, 174, 174, 174, 1040, 39, 39,
-	556, 662, 221, 156, 212, 212, 77, 77, 77, 131,
-	-1000, -1000, 82, 648, -1000, -1000, -1000, 173, 529, 82,
-	82, 529, -1000, 529, 529, 175, 68, -1000, 529, 175,
-	-3, 1040, -1000, -1000, 273, 673, 673, 884, -1000, -1000,
-	-1000, 529, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-	-1000, -1000, 107, -1000, -1000, 529, 82, 63, -1000, -25,
-	-1000, 35, 15, 529, -1000, -1000, 433, 727, -16, -27,
-	1040, -1000, 1040, -35, -1000, -1000, -1000, 988, -26, -1000,
-	-1000, 529, -1000, -1000, 86, 92, 86, 7, 857, -1000,
-	60, -1000, 1040, -1000, -1000, 82, -1000, 648, 82, 82,
-	832, -1000, 699, -1000, 529, 529, 123, 66, -1000, 6,
-	175, 1040, 673, 673, -1000, -1000, 174, -1000, -1000, -1000,
-	-1000, 5, -1000, 961, 936, 104, 529, 529, -1000, 529,
-	-1000, 92, 86, -1000, 82, 529, 529, -1000, 1013, 1040,
-	19, -1000, 805, 49, 529, -1000, -1000, -1000, 529, 1040,
-	780, -1000,
+	-1000, -1000, 535, -1000, 535, 535, 535, 535, 535, 535,
+	535, 535, 535, 535, 535, -1000, 1071, 0, -1000, -1000,
+	-1000, 113, 302, 241, 89, 1062, 535, 98, 86, 174,
+	-39, 2, -1000, -1000, 535, -1000, 921, 71, 71, -1000,
+	-12, -1000, 49, 48, 535, -1000, -1000, -1000, -1000, 758,
+	-1000, 160, -1000, 588, 40, 40, 40, 1071, 153, 153,
+	561, 201, 219, 67, 79, 79, 43, 43, 43, 131,
+	-1000, -1000, 0, 654, -1000, -1000, -1000, 39, 535, 0,
+	0, 535, -1000, 535, 535, 162, 64, -1000, 535, 162,
+	-5, 1071, -1000, -1000, 273, 678, 678, 897, -1000, -1000,
+	-1000, 535, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
+	-1000, -1000, 7, -1000, -1000, 535, 0, 5, -1000, -13,
+	-1000, 46, 41, 535, -1000, -1000, 435, 734, 12, 11,
+	1071, -1000, 1071, -39, -1000, -1000, -1000, 1005, -30, -1000,
+	-1000, 535, -1000, -1000, 77, 71, 77, 16, 867, -1000,
+	-20, -1000, 1071, -1000, -1000, 0, -1000, 654, 0, 0,
+	843, -1000, 703, -1000, 535, 535, 117, 57, -1000, -4,
+	162, 1071, 678, 678, -1000, -1000, 40, -1000, -1000, -1000,
+	-1000, -29, -1000, 986, 975, 101, 535, 535, -1000, 535,
+	-1000, 71, 77, -1000, 0, 535, 535, -1000, 1040, 1071,
+	951, -1000, 813, 172, 535, -1000, -1000, -1000, 535, 1071,
+	789, -1000,
 }
 
 var yyPgo = [...]int{
-	0, 299, 296, 282, 277, 276, 12, 198, 244, 273,
-	0, 264, 13, 259, 252, 10, 4, 9, 251, 20,
-	241, 240, 233, 227, 217, 8, 1, 2, 7, 214,
-	15, 213, 208, 5, 201, 187, 14, 3,
+	0, 264, 263, 262, 261, 259, 12, 214, 195, 244,
+	0, 241, 13, 240, 234, 10, 4, 9, 233, 20,
+	230, 218, 217, 215, 213, 8, 1, 2, 7, 199,
+	15, 198, 196, 5, 193, 192, 14, 3,
 }
 
 var yyR1 = [...]int{
@@ -366,35 +373,35 @@ var yyR2 = [...]int{
 }
 
 var yyChk = [...]int{
-	-1000, -1, -2, 10, -3, -4, -28, 60, -7, -10,
-	-5, -8, -16, 39, 40, 32, 37, 15, 11, 12,
-	13, 52, 41, 24, 17, 18, 19, -34, -35, 25,
-	26, -17, 57, 47, 48, 60, 54, 16, 20, 22,
-	21, 23, 28, 29, 55, 61, -29, -30, 20, -36,
-	28, 7, 8, 10, 11, 12, 13, 14, 15, 16,
-	17, 18, 19, 32, 33, 34, 35, 36, 37, 38,
-	39, 40, 45, 53, 46, 4, 5, 7, 8, 9,
-	47, 48, 49, 50, 51, -7, -10, 14, 24, -19,
-	53, 52, 54, -16, -16, -10, -8, -10, 21, 28,
-	28, 20, -19, -17, 57, -17, -10, -16, -16, 61,
-	-24, -25, -37, -17, 57, 20, 21, -36, 59, -10,
-	21, -18, 61, 46, 56, 56, 56, -10, -10, -10,
+	-1000, -1, -2, 10, -3, -4, -28, 62, -7, -10,
+	-5, -8, -16, 38, 39, 31, 36, 15, 11, 12,
+	13, 54, 40, 24, 17, 18, 19, -34, -35, 25,
+	26, -17, 59, 49, 50, 62, 56, 16, 20, 22,
+	21, 23, 27, 28, 57, 63, -29, -30, 20, -36,
+	27, 7, 8, 10, 11, 12, 13, 14, 15, 16,
+	17, 18, 19, 31, 32, 33, 34, 35, 36, 37,
+	38, 39, 47, 55, 48, 4, 5, 7, 8, 9,
+	49, 50, 51, 52, 53, -7, -10, 14, 24, -19,
+	55, 54, 56, -16, -16, -10, -8, -10, 21, 27,
+	27, 20, -19, -17, 59, -17, -10, -16, -16, 63,
+	-24, -25, -37, -17, 59, 20, 21, -36, 61, -10,
+	21, -18, 63, 48, 58, 58, 58, -10, -10, -10,
 	-10, -10, -10, -10, -10, -10, -10, -10, -10, -11,
-	-12, 21, 54, 60, -19, -17, 59, -10, 56, 14,
-	14, 33, -23, 38, 45, 14, -6, -28, 56, 57,
-	-20, -10, 58, 61, 46, 56, 56, -10, 59, 31,
-	28, 30, 61, -30, -27, -28, -31, 25, 28, 17,
-	18, 19, 54, -27, -27, 45, 6, -13, -12, -14,
-	-15, -37, -17, 57, 21, 59, 56, -10, -12, -12,
-	-10, -10, -10, -33, 20, 21, 55, -10, -9, -33,
-	58, 55, 61, -25, -26, -16, -26, 58, -10, 59,
-	-32, -27, -10, -12, 59, 46, 61, 46, 56, 56,
-	-10, 59, -10, 59, 57, 57, -21, -6, 55, 58,
-	55, -10, 45, 56, 58, 59, 46, -12, -15, -12,
-	-12, 58, 59, -10, -10, -22, 34, 35, 55, 56,
-	-33, -16, -26, -27, 56, 55, 55, 36, -10, -10,
-	-10, -12, -10, -10, 33, 55, 58, 58, 55, -10,
-	-10, 58,
+	-12, 21, 56, 62, -19, -17, 61, -10, 58, 14,
+	14, 32, -23, 37, 47, 14, -6, -28, 58, 59,
+	-20, -10, 60, 63, 48, 58, 58, -10, 61, 30,
+	27, 29, 63, -30, -27, -28, -31, 25, 27, 17,
+	18, 19, 56, -27, -27, 47, 6, -13, -12, -14,
+	-15, -37, -17, 59, 21, 61, 58, -10, -12, -12,
+	-10, -10, -10, -33, 20, 21, 57, -10, -9, -33,
+	60, 57, 63, -25, -26, -16, -26, 60, -10, 61,
+	-32, -27, -10, -12, 61, 48, 63, 48, 58, 58,
+	-10, 61, -10, 61, 59, 59, -21, -6, 57, 60,
+	57, -10, 47, 58, 60, 61, 48, -12, -15, -12,
+	-12, 60, 61, -10, -10, -22, 33, 34, 57, 58,
+	-33, -16, -26, -27, 58, 57, 57, 35, -10, -10,
+	-10, -12, -10, -10, 32, 57, 60, 60, 57, -10,
+	-10, 60,
 }
 
 var yyDef = [...]int{
@@ -433,16 +440,16 @@ var yyTok1 = [...]int{
 	1, 3, 3, 3, 3, 3, 3, 3, 3, 3,
 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
-	3, 3, 3, 3, 3, 3, 3, 51, 3, 3,
-	57, 58, 49, 47, 46, 48, 52, 50, 3, 3,
-	3, 3, 3, 3, 3, 3, 3, 3, 56, 55,
-	3, 3, 3, 53, 3, 3, 3, 3, 3, 3,
+	3, 3, 3, 3, 3, 3, 3, 53, 3, 3,
+	59, 60, 51, 49, 48, 50, 54, 52, 3, 3,
+	3, 3, 3, 3, 3, 3, 3, 3, 58, 57,
+	3, 3, 3, 55, 3, 3, 3, 3, 3, 3,
 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
-	3, 54, 3, 59, 3, 3, 3, 3, 3, 3,
+	3, 56, 3, 61, 3, 3, 3, 3, 3, 3,
 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
-	3, 3, 3, 60, 45, 61,
+	3, 3, 3, 62, 47, 63,
 }
 
 var yyTok2 = [...]int{
@@ -450,7 +457,7 @@ var yyTok2 = [...]int{
 	12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
 	22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
 	32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
-	42, 43, 44,
+	42, 43, 44, 45, 46,
 }
 
 var yyTok3 = [...]int{
@@ -796,7 +803,7 @@ yydefault:
 
 	case 1:
 		yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:67
+//line parser.go.y:68
 		{
 			if yyDollar[1].value != nil {
 				yyDollar[2].value.(*Query).Meta = yyDollar[1].value.(*ConstObject)
@@ -805,25 +812,25 @@ yydefault:
 		}
 	case 2:
 		yyDollar = yyS[yypt-0 : yypt+1]
-//line parser.go.y:74
+//line parser.go.y:75
 		{
 			yyVAL.value = nil
 		}
 	case 3:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:78
+//line parser.go.y:79
 		{
 			yyVAL.value = yyDollar[2].value
 		}
 	case 4:
 		yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:84
+//line parser.go.y:85
 		{
 			yyVAL.value = &Query{Imports: yyDollar[1].value.([]*Import), FuncDefs: reverseFuncDef(yyDollar[2].value.([]*FuncDef)), Term: &Term{Type: TermTypeIdentity}}
 		}
 	case 5:
 		yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:88
+//line parser.go.y:89
 		{
 			if yyDollar[1].value != nil {
 				yyDollar[2].value.(*Query).Imports = yyDollar[1].value.([]*Import)
@@ -832,144 +839,144 @@ yydefault:
 		}
 	case 6:
 		yyDollar = yyS[yypt-0 : yypt+1]
-//line parser.go.y:95
+//line parser.go.y:96
 		{
 			yyVAL.value = []*Import(nil)
 		}
 	case 7:
 		yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:99
+//line parser.go.y:100
 		{
 			yyVAL.value = append(yyDollar[1].value.([]*Import), yyDollar[2].value.(*Import))
 		}
 	case 8:
 		yyDollar = yyS[yypt-6 : yypt+1]
-//line parser.go.y:105
+//line parser.go.y:106
 		{
 			yyVAL.value = &Import{ImportPath: yyDollar[2].token, ImportAlias: yyDollar[4].token, Meta: yyDollar[5].value.(*ConstObject)}
 		}
 	case 9:
 		yyDollar = yyS[yypt-4 : yypt+1]
-//line parser.go.y:109
+//line parser.go.y:110
 		{
 			yyVAL.value = &Import{IncludePath: yyDollar[2].token, Meta: yyDollar[3].value.(*ConstObject)}
 		}
 	case 10:
 		yyDollar = yyS[yypt-0 : yypt+1]
-//line parser.go.y:115
+//line parser.go.y:116
 		{
 			yyVAL.value = (*ConstObject)(nil)
 		}
 	case 11:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:118
+//line parser.go.y:119
 		{
 		}
 	case 12:
 		yyDollar = yyS[yypt-0 : yypt+1]
-//line parser.go.y:122
+//line parser.go.y:123
 		{
 			yyVAL.value = []*FuncDef(nil)
 		}
 	case 13:
 		yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:126
+//line parser.go.y:127
 		{
 			yyVAL.value = append(yyDollar[2].value.([]*FuncDef), yyDollar[1].value.(*FuncDef))
 		}
 	case 14:
 		yyDollar = yyS[yypt-5 : yypt+1]
-//line parser.go.y:132
+//line parser.go.y:133
 		{
 			yyVAL.value = &FuncDef{Name: yyDollar[2].token, Body: yyDollar[4].value.(*Query)}
 		}
 	case 15:
 		yyDollar = yyS[yypt-8 : yypt+1]
-//line parser.go.y:136
+//line parser.go.y:137
 		{
 			yyVAL.value = &FuncDef{yyDollar[2].token, yyDollar[4].value.([]string), yyDollar[7].value.(*Query)}
 		}
 	case 16:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:142
+//line parser.go.y:143
 		{
 			yyVAL.value = []string{yyDollar[1].token}
 		}
 	case 17:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:146
+//line parser.go.y:147
 		{
 			yyVAL.value = append(yyDollar[1].value.([]string), yyDollar[3].token)
 		}
 	case 18:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:151
+//line parser.go.y:152
 		{
 		}
 	case 19:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:152
+//line parser.go.y:153
 		{
 		}
 	case 20:
 		yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:156
+//line parser.go.y:157
 		{
 			yyDollar[2].value.(*Query).FuncDefs = prependFuncDef(yyDollar[2].value.(*Query).FuncDefs, yyDollar[1].value.(*FuncDef))
 			yyVAL.value = yyDollar[2].value
 		}
 	case 21:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:161
+//line parser.go.y:162
 		{
 			yyVAL.value = &Query{Left: yyDollar[1].value.(*Query), Op: OpPipe, Right: yyDollar[3].value.(*Query)}
 		}
 	case 22:
 		yyDollar = yyS[yypt-5 : yypt+1]
-//line parser.go.y:165
+//line parser.go.y:166
 		{
 			yyDollar[1].value.(*Term).SuffixList = append(yyDollar[1].value.(*Term).SuffixList, &Suffix{Bind: &Bind{yyDollar[3].value.([]*Pattern), yyDollar[5].value.(*Query)}})
 			yyVAL.value = &Query{Term: yyDollar[1].value.(*Term)}
 		}
 	case 23:
 		yyDollar = yyS[yypt-9 : yypt+1]
-//line parser.go.y:170
+//line parser.go.y:171
 		{
 			yyVAL.value = &Query{Term: &Term{Type: TermTypeReduce, Reduce: &Reduce{yyDollar[2].value.(*Term), yyDollar[4].value.(*Pattern), yyDollar[6].value.(*Query), yyDollar[8].value.(*Query)}}}
 		}
 	case 24:
 		yyDollar = yyS[yypt-9 : yypt+1]
-//line parser.go.y:174
+//line parser.go.y:175
 		{
 			yyVAL.value = &Query{Term: &Term{Type: TermTypeForeach, Foreach: &Foreach{yyDollar[2].value.(*Term), yyDollar[4].value.(*Pattern), yyDollar[6].value.(*Query), yyDollar[8].value.(*Query), nil}}}
 		}
 	case 25:
 		yyDollar = yyS[yypt-11 : yypt+1]
-//line parser.go.y:178
+//line parser.go.y:179
 		{
 			yyVAL.value = &Query{Term: &Term{Type: TermTypeForeach, Foreach: &Foreach{yyDollar[2].value.(*Term), yyDollar[4].value.(*Pattern), yyDollar[6].value.(*Query), yyDollar[8].value.(*Query), yyDollar[10].value.(*Query)}}}
 		}
 	case 26:
 		yyDollar = yyS[yypt-7 : yypt+1]
-//line parser.go.y:182
+//line parser.go.y:183
 		{
 			yyVAL.value = &Query{Term: &Term{Type: TermTypeIf, If: &If{yyDollar[2].value.(*Query), yyDollar[4].value.(*Query), yyDollar[5].value.([]*IfElif), yyDollar[6].value.(*Query)}}}
 		}
 	case 27:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:186
+//line parser.go.y:187
 		{
 			yyVAL.value = &Query{Term: &Term{Type: TermTypeTry, Try: &Try{yyDollar[2].value.(*Query), yyDollar[3].value.(*Query)}}}
 		}
 	case 28:
 		yyDollar = yyS[yypt-4 : yypt+1]
-//line parser.go.y:190
+//line parser.go.y:191
 		{
 			yyVAL.value = &Query{Term: &Term{Type: TermTypeLabel, Label: &Label{yyDollar[2].token, yyDollar[4].value.(*Query)}}}
 		}
 	case 29:
 		yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:194
+//line parser.go.y:195
 		{
 			if t := yyDollar[1].value.(*Query).Term; t != nil {
 				t.SuffixList = append(t.SuffixList, &Suffix{Optional: true})
@@ -979,175 +986,175 @@ yydefault:
 		}
 	case 30:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:202
+//line parser.go.y:203
 		{
 			yyVAL.value = &Query{Left: yyDollar[1].value.(*Query), Op: OpComma, Right: yyDollar[3].value.(*Query)}
 		}
 	case 31:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:206
+//line parser.go.y:207
 		{
 			yyVAL.value = &Query{Left: yyDollar[1].value.(*Query), Op: yyDollar[2].operator, Right: yyDollar[3].value.(*Query)}
 		}
 	case 32:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:210
+//line parser.go.y:211
 		{
 			yyVAL.value = &Query{Left: yyDollar[1].value.(*Query), Op: yyDollar[2].operator, Right: yyDollar[3].value.(*Query)}
 		}
 	case 33:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:214
+//line parser.go.y:215
 		{
 			yyVAL.value = &Query{Left: yyDollar[1].value.(*Query), Op: OpOr, Right: yyDollar[3].value.(*Query)}
 		}
 	case 34:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:218
+//line parser.go.y:219
 		{
 			yyVAL.value = &Query{Left: yyDollar[1].value.(*Query), Op: OpAnd, Right: yyDollar[3].value.(*Query)}
 		}
 	case 35:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:222
+//line parser.go.y:223
 		{
 			yyVAL.value = &Query{Left: yyDollar[1].value.(*Query), Op: yyDollar[2].operator, Right: yyDollar[3].value.(*Query)}
 		}
 	case 36:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:226
+//line parser.go.y:227
 		{
 			yyVAL.value = &Query{Left: yyDollar[1].value.(*Query), Op: OpAdd, Right: yyDollar[3].value.(*Query)}
 		}
 	case 37:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:230
+//line parser.go.y:231
 		{
 			yyVAL.value = &Query{Left: yyDollar[1].value.(*Query), Op: OpSub, Right: yyDollar[3].value.(*Query)}
 		}
 	case 38:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:234
+//line parser.go.y:235
 		{
 			yyVAL.value = &Query{Left: yyDollar[1].value.(*Query), Op: OpMul, Right: yyDollar[3].value.(*Query)}
 		}
 	case 39:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:238
+//line parser.go.y:239
 		{
 			yyVAL.value = &Query{Left: yyDollar[1].value.(*Query), Op: OpDiv, Right: yyDollar[3].value.(*Query)}
 		}
 	case 40:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:242
+//line parser.go.y:243
 		{
 			yyVAL.value = &Query{Left: yyDollar[1].value.(*Query), Op: OpMod, Right: yyDollar[3].value.(*Query)}
 		}
 	case 41:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:246
+//line parser.go.y:247
 		{
 			yyVAL.value = &Query{Term: yyDollar[1].value.(*Term)}
 		}
 	case 42:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:252
+//line parser.go.y:253
 		{
 			yyVAL.value = []*Pattern{yyDollar[1].value.(*Pattern)}
 		}
 	case 43:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:256
+//line parser.go.y:257
 		{
 			yyVAL.value = append(yyDollar[1].value.([]*Pattern), yyDollar[3].value.(*Pattern))
 		}
 	case 44:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:262
+//line parser.go.y:263
 		{
 			yyVAL.value = &Pattern{Name: yyDollar[1].token}
 		}
 	case 45:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:266
+//line parser.go.y:267
 		{
 			yyVAL.value = &Pattern{Array: yyDollar[2].value.([]*Pattern)}
 		}
 	case 46:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:270
+//line parser.go.y:271
 		{
 			yyVAL.value = &Pattern{Object: yyDollar[2].value.([]*PatternObject)}
 		}
 	case 47:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:276
+//line parser.go.y:277
 		{
 			yyVAL.value = []*Pattern{yyDollar[1].value.(*Pattern)}
 		}
 	case 48:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:280
+//line parser.go.y:281
 		{
 			yyVAL.value = append(yyDollar[1].value.([]*Pattern), yyDollar[3].value.(*Pattern))
 		}
 	case 49:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:286
+//line parser.go.y:287
 		{
 			yyVAL.value = []*PatternObject{yyDollar[1].value.(*PatternObject)}
 		}
 	case 50:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:290
+//line parser.go.y:291
 		{
 			yyVAL.value = append(yyDollar[1].value.([]*PatternObject), yyDollar[3].value.(*PatternObject))
 		}
 	case 51:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:296
+//line parser.go.y:297
 		{
 			yyVAL.value = &PatternObject{Key: yyDollar[1].token, Val: yyDollar[3].value.(*Pattern)}
 		}
 	case 52:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:300
+//line parser.go.y:301
 		{
 			yyVAL.value = &PatternObject{KeyString: yyDollar[1].value.(*String), Val: yyDollar[3].value.(*Pattern)}
 		}
 	case 53:
 		yyDollar = yyS[yypt-5 : yypt+1]
-//line parser.go.y:304
+//line parser.go.y:305
 		{
 			yyVAL.value = &PatternObject{KeyQuery: yyDollar[2].value.(*Query), Val: yyDollar[5].value.(*Pattern)}
 		}
 	case 54:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:308
+//line parser.go.y:309
 		{
-			yyVAL.value = &PatternObject{KeyOnly: yyDollar[1].token}
+			yyVAL.value = &PatternObject{Key: yyDollar[1].token}
 		}
 	case 55:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:314
+//line parser.go.y:315
 		{
 			yyVAL.value = &Term{Type: TermTypeIdentity}
 		}
 	case 56:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:318
+//line parser.go.y:319
 		{
 			yyVAL.value = &Term{Type: TermTypeRecurse}
 		}
 	case 57:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:322
+//line parser.go.y:323
 		{
 			yyVAL.value = &Term{Type: TermTypeIndex, Index: &Index{Name: yyDollar[1].token}}
 		}
 	case 58:
 		yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:326
+//line parser.go.y:327
 		{
 			if yyDollar[2].value.(*Suffix).Iter {
 				yyVAL.value = &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{yyDollar[2].value.(*Suffix)}}
@@ -1157,569 +1164,569 @@ yydefault:
 		}
 	case 59:
 		yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:334
+//line parser.go.y:335
 		{
 			yyVAL.value = &Term{Type: TermTypeIndex, Index: &Index{Str: yyDollar[2].value.(*String)}}
 		}
 	case 60:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:338
+//line parser.go.y:339
 		{
 			yyVAL.value = &Term{Type: TermTypeNull}
 		}
 	case 61:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:342
+//line parser.go.y:343
 		{
 			yyVAL.value = &Term{Type: TermTypeTrue}
 		}
 	case 62:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:346
+//line parser.go.y:347
 		{
 			yyVAL.value = &Term{Type: TermTypeFalse}
 		}
 	case 63:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:350
+//line parser.go.y:351
 		{
 			yyVAL.value = &Term{Type: TermTypeFunc, Func: &Func{Name: yyDollar[1].token}}
 		}
 	case 64:
 		yyDollar = yyS[yypt-4 : yypt+1]
-//line parser.go.y:354
+//line parser.go.y:355
 		{
 			yyVAL.value = &Term{Type: TermTypeFunc, Func: &Func{Name: yyDollar[1].token, Args: yyDollar[3].value.([]*Query)}}
 		}
 	case 65:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:358
+//line parser.go.y:359
 		{
 			yyVAL.value = &Term{Type: TermTypeFunc, Func: &Func{Name: yyDollar[1].token}}
 		}
 	case 66:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:362
+//line parser.go.y:363
 		{
 			yyVAL.value = &Term{Type: TermTypeNumber, Number: yyDollar[1].token}
 		}
 	case 67:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:366
+//line parser.go.y:367
 		{
 			yyVAL.value = &Term{Type: TermTypeFormat, Format: yyDollar[1].token}
 		}
 	case 68:
 		yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:370
+//line parser.go.y:371
 		{
 			yyVAL.value = &Term{Type: TermTypeFormat, Format: yyDollar[1].token, Str: yyDollar[2].value.(*String)}
 		}
 	case 69:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:374
+//line parser.go.y:375
 		{
 			yyVAL.value = &Term{Type: TermTypeString, Str: yyDollar[1].value.(*String)}
 		}
 	case 70:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:378
+//line parser.go.y:379
 		{
 			yyVAL.value = &Term{Type: TermTypeQuery, Query: yyDollar[2].value.(*Query)}
 		}
 	case 71:
 		yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:382
+//line parser.go.y:383
 		{
 			yyVAL.value = &Term{Type: TermTypeUnary, Unary: &Unary{OpAdd, yyDollar[2].value.(*Term)}}
 		}
 	case 72:
 		yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:386
+//line parser.go.y:387
 		{
 			yyVAL.value = &Term{Type: TermTypeUnary, Unary: &Unary{OpSub, yyDollar[2].value.(*Term)}}
 		}
 	case 73:
 		yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:390
+//line parser.go.y:391
 		{
 			yyVAL.value = &Term{Type: TermTypeObject, Object: &Object{}}
 		}
 	case 74:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:394
+//line parser.go.y:395
 		{
 			yyVAL.value = &Term{Type: TermTypeObject, Object: &Object{yyDollar[2].value.([]*ObjectKeyVal)}}
 		}
 	case 75:
 		yyDollar = yyS[yypt-4 : yypt+1]
-//line parser.go.y:398
+//line parser.go.y:399
 		{
 			yyVAL.value = &Term{Type: TermTypeObject, Object: &Object{yyDollar[2].value.([]*ObjectKeyVal)}}
 		}
 	case 76:
 		yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:402
+//line parser.go.y:403
 		{
 			yyVAL.value = &Term{Type: TermTypeArray, Array: &Array{}}
 		}
 	case 77:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:406
+//line parser.go.y:407
 		{
 			yyVAL.value = &Term{Type: TermTypeArray, Array: &Array{yyDollar[2].value.(*Query)}}
 		}
 	case 78:
 		yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:410
+//line parser.go.y:411
 		{
 			yyVAL.value = &Term{Type: TermTypeBreak, Break: yyDollar[2].token}
 		}
 	case 79:
 		yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:414
+//line parser.go.y:415
 		{
 			yyDollar[1].value.(*Term).SuffixList = append(yyDollar[1].value.(*Term).SuffixList, &Suffix{Index: &Index{Name: yyDollar[2].token}})
 		}
 	case 80:
 		yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:418
+//line parser.go.y:419
 		{
 			yyDollar[1].value.(*Term).SuffixList = append(yyDollar[1].value.(*Term).SuffixList, yyDollar[2].value.(*Suffix))
 		}
 	case 81:
 		yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:422
+//line parser.go.y:423
 		{
 			yyDollar[1].value.(*Term).SuffixList = append(yyDollar[1].value.(*Term).SuffixList, &Suffix{Optional: true})
 		}
 	case 82:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:426
+//line parser.go.y:427
 		{
 			yyDollar[1].value.(*Term).SuffixList = append(yyDollar[1].value.(*Term).SuffixList, yyDollar[3].value.(*Suffix))
 		}
 	case 83:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:430
+//line parser.go.y:431
 		{
 			yyDollar[1].value.(*Term).SuffixList = append(yyDollar[1].value.(*Term).SuffixList, &Suffix{Index: &Index{Str: yyDollar[3].value.(*String)}})
 		}
 	case 84:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:436
+//line parser.go.y:437
 		{
 			yyVAL.value = &String{Str: yyDollar[1].token}
 		}
 	case 85:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:440
+//line parser.go.y:441
 		{
 			yyVAL.value = &String{Queries: yyDollar[2].value.([]*Query)}
 		}
 	case 86:
 		yyDollar = yyS[yypt-0 : yypt+1]
-//line parser.go.y:446
+//line parser.go.y:447
 		{
 			yyVAL.value = []*Query{}
 		}
 	case 87:
 		yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:450
+//line parser.go.y:451
 		{
 			yyVAL.value = append(yyDollar[1].value.([]*Query), &Query{Term: &Term{Type: TermTypeString, Str: &String{Str: yyDollar[2].token}}})
 		}
 	case 88:
 		yyDollar = yyS[yypt-4 : yypt+1]
-//line parser.go.y:454
+//line parser.go.y:455
 		{
 			yylex.(*lexer).inString = true
 			yyVAL.value = append(yyDollar[1].value.([]*Query), &Query{Term: &Term{Type: TermTypeQuery, Query: yyDollar[3].value.(*Query)}})
 		}
 	case 89:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:460
+//line parser.go.y:461
 		{
 		}
 	case 90:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:461
+//line parser.go.y:462
 		{
 		}
 	case 91:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:464
+//line parser.go.y:465
 		{
 		}
 	case 92:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:465
+//line parser.go.y:466
 		{
 		}
 	case 93:
 		yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:469
+//line parser.go.y:470
 		{
 			yyVAL.value = &Suffix{Iter: true}
 		}
 	case 94:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:473
+//line parser.go.y:474
 		{
 			yyVAL.value = &Suffix{Index: &Index{Start: yyDollar[2].value.(*Query)}}
 		}
 	case 95:
 		yyDollar = yyS[yypt-4 : yypt+1]
-//line parser.go.y:477
+//line parser.go.y:478
 		{
 			yyVAL.value = &Suffix{Index: &Index{Start: yyDollar[2].value.(*Query), IsSlice: true}}
 		}
 	case 96:
 		yyDollar = yyS[yypt-4 : yypt+1]
-//line parser.go.y:481
+//line parser.go.y:482
 		{
 			yyVAL.value = &Suffix{Index: &Index{End: yyDollar[3].value.(*Query), IsSlice: true}}
 		}
 	case 97:
 		yyDollar = yyS[yypt-5 : yypt+1]
-//line parser.go.y:485
+//line parser.go.y:486
 		{
 			yyVAL.value = &Suffix{Index: &Index{Start: yyDollar[2].value.(*Query), End: yyDollar[4].value.(*Query), IsSlice: true}}
 		}
 	case 98:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:491
+//line parser.go.y:492
 		{
 			yyVAL.value = []*Query{yyDollar[1].value.(*Query)}
 		}
 	case 99:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:495
+//line parser.go.y:496
 		{
 			yyVAL.value = append(yyDollar[1].value.([]*Query), yyDollar[3].value.(*Query))
 		}
 	case 100:
 		yyDollar = yyS[yypt-0 : yypt+1]
-//line parser.go.y:501
+//line parser.go.y:502
 		{
 			yyVAL.value = []*IfElif(nil)
 		}
 	case 101:
 		yyDollar = yyS[yypt-5 : yypt+1]
-//line parser.go.y:505
+//line parser.go.y:506
 		{
 			yyVAL.value = append(yyDollar[1].value.([]*IfElif), &IfElif{yyDollar[3].value.(*Query), yyDollar[5].value.(*Query)})
 		}
 	case 102:
 		yyDollar = yyS[yypt-0 : yypt+1]
-//line parser.go.y:511
+//line parser.go.y:512
 		{
 			yyVAL.value = (*Query)(nil)
 		}
 	case 103:
 		yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:515
+//line parser.go.y:516
 		{
 			yyVAL.value = yyDollar[2].value
 		}
 	case 104:
 		yyDollar = yyS[yypt-0 : yypt+1]
-//line parser.go.y:521
+//line parser.go.y:522
 		{
 			yyVAL.value = (*Query)(nil)
 		}
 	case 105:
 		yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:525
+//line parser.go.y:526
 		{
 			yyVAL.value = yyDollar[2].value
 		}
 	case 106:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:531
+//line parser.go.y:532
 		{
 			yyVAL.value = []*ObjectKeyVal{yyDollar[1].value.(*ObjectKeyVal)}
 		}
 	case 107:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:535
+//line parser.go.y:536
 		{
 			yyVAL.value = append(yyDollar[1].value.([]*ObjectKeyVal), yyDollar[3].value.(*ObjectKeyVal))
 		}
 	case 108:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:541
+//line parser.go.y:542
 		{
 			yyVAL.value = &ObjectKeyVal{Key: yyDollar[1].token, Val: yyDollar[3].value.(*ObjectVal)}
 		}
 	case 109:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:545
+//line parser.go.y:546
 		{
 			yyVAL.value = &ObjectKeyVal{KeyString: yyDollar[1].value.(*String), Val: yyDollar[3].value.(*ObjectVal)}
 		}
 	case 110:
 		yyDollar = yyS[yypt-5 : yypt+1]
-//line parser.go.y:549
+//line parser.go.y:550
 		{
 			yyVAL.value = &ObjectKeyVal{KeyQuery: yyDollar[2].value.(*Query), Val: yyDollar[5].value.(*ObjectVal)}
 		}
 	case 111:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:553
+//line parser.go.y:554
 		{
-			yyVAL.value = &ObjectKeyVal{KeyOnly: yyDollar[1].token}
+			yyVAL.value = &ObjectKeyVal{Key: yyDollar[1].token}
 		}
 	case 112:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:557
+//line parser.go.y:558
 		{
-			yyVAL.value = &ObjectKeyVal{KeyOnlyString: yyDollar[1].value.(*String)}
+			yyVAL.value = &ObjectKeyVal{KeyString: yyDollar[1].value.(*String)}
 		}
 	case 113:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:562
+//line parser.go.y:563
 		{
 		}
 	case 114:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:563
+//line parser.go.y:564
 		{
 		}
 	case 115:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:564
+//line parser.go.y:565
 		{
 		}
 	case 116:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:568
+//line parser.go.y:569
 		{
 			yyVAL.value = &ObjectVal{[]*Query{{Term: yyDollar[1].value.(*Term)}}}
 		}
 	case 117:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:572
+//line parser.go.y:573
 		{
 			yyVAL.value = &ObjectVal{append(yyDollar[1].value.(*ObjectVal).Queries, &Query{Term: yyDollar[3].value.(*Term)})}
 		}
 	case 118:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:578
+//line parser.go.y:579
 		{
 			yyVAL.value = &ConstTerm{Object: yyDollar[1].value.(*ConstObject)}
 		}
 	case 119:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:582
+//line parser.go.y:583
 		{
 			yyVAL.value = &ConstTerm{Array: yyDollar[1].value.(*ConstArray)}
 		}
 	case 120:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:586
+//line parser.go.y:587
 		{
 			yyVAL.value = &ConstTerm{Number: yyDollar[1].token}
 		}
 	case 121:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:590
+//line parser.go.y:591
 		{
 			yyVAL.value = &ConstTerm{Str: yyDollar[1].token}
 		}
 	case 122:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:594
+//line parser.go.y:595
 		{
 			yyVAL.value = &ConstTerm{Null: true}
 		}
 	case 123:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:598
+//line parser.go.y:599
 		{
 			yyVAL.value = &ConstTerm{True: true}
 		}
 	case 124:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:602
+//line parser.go.y:603
 		{
 			yyVAL.value = &ConstTerm{False: true}
 		}
 	case 125:
 		yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:608
+//line parser.go.y:609
 		{
 			yyVAL.value = &ConstObject{}
 		}
 	case 126:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:612
+//line parser.go.y:613
 		{
 			yyVAL.value = &ConstObject{yyDollar[2].value.([]*ConstObjectKeyVal)}
 		}
 	case 127:
 		yyDollar = yyS[yypt-4 : yypt+1]
-//line parser.go.y:616
+//line parser.go.y:617
 		{
 			yyVAL.value = &ConstObject{yyDollar[2].value.([]*ConstObjectKeyVal)}
 		}
 	case 128:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:622
+//line parser.go.y:623
 		{
 			yyVAL.value = []*ConstObjectKeyVal{yyDollar[1].value.(*ConstObjectKeyVal)}
 		}
 	case 129:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:626
+//line parser.go.y:627
 		{
 			yyVAL.value = append(yyDollar[1].value.([]*ConstObjectKeyVal), yyDollar[3].value.(*ConstObjectKeyVal))
 		}
 	case 130:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:632
+//line parser.go.y:633
 		{
 			yyVAL.value = &ConstObjectKeyVal{Key: yyDollar[1].token, Val: yyDollar[3].value.(*ConstTerm)}
 		}
 	case 131:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:636
+//line parser.go.y:637
 		{
 			yyVAL.value = &ConstObjectKeyVal{Key: yyDollar[1].token, Val: yyDollar[3].value.(*ConstTerm)}
 		}
 	case 132:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:640
+//line parser.go.y:641
 		{
 			yyVAL.value = &ConstObjectKeyVal{KeyString: yyDollar[1].token, Val: yyDollar[3].value.(*ConstTerm)}
 		}
 	case 133:
 		yyDollar = yyS[yypt-2 : yypt+1]
-//line parser.go.y:646
+//line parser.go.y:647
 		{
 			yyVAL.value = &ConstArray{}
 		}
 	case 134:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:650
+//line parser.go.y:651
 		{
 			yyVAL.value = &ConstArray{yyDollar[2].value.([]*ConstTerm)}
 		}
 	case 135:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:656
+//line parser.go.y:657
 		{
 			yyVAL.value = []*ConstTerm{yyDollar[1].value.(*ConstTerm)}
 		}
 	case 136:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line parser.go.y:660
+//line parser.go.y:661
 		{
 			yyVAL.value = append(yyDollar[1].value.([]*ConstTerm), yyDollar[3].value.(*ConstTerm))
 		}
 	case 137:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:665
+//line parser.go.y:666
 		{
 		}
 	case 138:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:666
+//line parser.go.y:667
 		{
 		}
 	case 139:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:667
+//line parser.go.y:668
 		{
 		}
 	case 140:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:668
+//line parser.go.y:669
 		{
 		}
 	case 141:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:669
+//line parser.go.y:670
 		{
 		}
 	case 142:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:670
+//line parser.go.y:671
 		{
 		}
 	case 143:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:671
+//line parser.go.y:672
 		{
 		}
 	case 144:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:672
+//line parser.go.y:673
 		{
 		}
 	case 145:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:673
+//line parser.go.y:674
 		{
 		}
 	case 146:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:674
+//line parser.go.y:675
 		{
 		}
 	case 147:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:675
+//line parser.go.y:676
 		{
 		}
 	case 148:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:676
+//line parser.go.y:677
 		{
 		}
 	case 149:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:677
+//line parser.go.y:678
 		{
 		}
 	case 150:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:678
+//line parser.go.y:679
 		{
 		}
 	case 151:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:679
+//line parser.go.y:680
 		{
 		}
 	case 152:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:680
+//line parser.go.y:681
 		{
 		}
 	case 153:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:681
+//line parser.go.y:682
 		{
 		}
 	case 154:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:682
+//line parser.go.y:683
 		{
 		}
 	case 155:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:683
+//line parser.go.y:684
 		{
 		}
 	case 156:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:684
+//line parser.go.y:685
 		{
 		}
 	case 157:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line parser.go.y:685
+//line parser.go.y:686
 		{
 		}
 	}
diff --git a/parser.go.y b/parser.go.y
index 5e2bc08..9176877 100644
--- a/parser.go.y
+++ b/parser.go.y
@@ -41,11 +41,12 @@ func prependFuncDef(xs []*FuncDef, x *FuncDef) []*FuncDef {
 %token<token> tokModule tokImport tokInclude tokDef tokAs tokLabel tokBreak
 %token<token> tokNull tokTrue tokFalse
 %token<token> tokIdent tokVariable tokModuleIdent tokModuleVariable
-%token<token> tokIndex tokNumber tokFormat tokInvalid
+%token<token> tokIndex tokNumber tokFormat
 %token<token> tokString tokStringStart tokStringQuery tokStringEnd
 %token<token> tokIf tokThen tokElif tokElse tokEnd
 %token<token> tokTry tokCatch tokReduce tokForeach
 %token tokRecurse tokFuncDefPost tokTermPost tokEmptyCatch
+%token tokInvalid tokInvalidEscape tokUnterminatedString
 
 %nonassoc tokFuncDefPost tokTermPost
 %right '|'
@@ -306,7 +307,7 @@ objectpattern
     }
     | tokVariable
     {
-        $$ = &PatternObject{KeyOnly: $1}
+        $$ = &PatternObject{Key: $1}
     }
 
 term
@@ -551,11 +552,11 @@ objectkeyval
     }
     | objectkey
     {
-        $$ = &ObjectKeyVal{KeyOnly: $1}
+        $$ = &ObjectKeyVal{Key: $1}
     }
     | string
     {
-        $$ = &ObjectKeyVal{KeyOnlyString: $1.(*String)}
+        $$ = &ObjectKeyVal{KeyString: $1.(*String)}
     }
 
 objectkey
diff --git a/query.go b/query.go
index 98b6502..12d0b40 100644
--- a/query.go
+++ b/query.go
@@ -2,8 +2,6 @@ package gojq
 
 import (
 	"context"
-	"encoding/json"
-	"strconv"
 	"strings"
 )
 
@@ -93,11 +91,18 @@ func (e *Query) minify() {
 	}
 }
 
-func (e *Query) toIndices() []interface{} {
-	if e.FuncDefs != nil || e.Right != nil || e.Term == nil {
+func (e *Query) toIndexKey() interface{} {
+	if e.Term == nil {
 		return nil
 	}
-	return e.Term.toIndices()
+	return e.Term.toIndexKey()
+}
+
+func (e *Query) toIndices(xs []interface{}) []interface{} {
+	if e.Term == nil {
+		return nil
+	}
+	return e.Term.toIndices(xs)
 }
 
 // Import ...
@@ -117,12 +122,12 @@ func (e *Import) String() string {
 func (e *Import) writeTo(s *strings.Builder) {
 	if e.ImportPath != "" {
 		s.WriteString("import ")
-		s.WriteString(strconv.Quote(e.ImportPath))
+		jsonEncodeString(s, e.ImportPath)
 		s.WriteString(" as ")
 		s.WriteString(e.ImportAlias)
 	} else {
 		s.WriteString("include ")
-		s.WriteString(strconv.Quote(e.IncludePath))
+		jsonEncodeString(s, e.IncludePath)
 	}
 	if e.Meta != nil {
 		s.WriteByte(' ')
@@ -308,25 +313,48 @@ func (e *Term) toFunc() string {
 	}
 }
 
-func (e *Term) toIndices() []interface{} {
-	if e.Index != nil {
-		xs := e.Index.toIndices()
-		if xs == nil {
+func (e *Term) toIndexKey() interface{} {
+	switch e.Type {
+	case TermTypeNumber:
+		return toNumber(e.Number)
+	case TermTypeUnary:
+		return e.Unary.toNumber()
+	case TermTypeString:
+		if e.Str.Queries == nil {
+			return e.Str.Str
+		}
+		return nil
+	default:
+		return nil
+	}
+}
+
+func (e *Term) toIndices(xs []interface{}) []interface{} {
+	switch e.Type {
+	case TermTypeIndex:
+		if xs = e.Index.toIndices(xs); xs == nil {
 			return nil
 		}
-		for _, s := range e.SuffixList {
-			x := s.toIndices()
-			if x == nil {
-				return nil
-			}
-			xs = append(xs, x...)
+	case TermTypeQuery:
+		if xs = e.Query.toIndices(xs); xs == nil {
+			return nil
 		}
-		return xs
-	} else if e.Query != nil && len(e.SuffixList) == 0 {
-		return e.Query.toIndices()
-	} else {
+	default:
 		return nil
 	}
+	for _, s := range e.SuffixList {
+		if xs = s.toIndices(xs); xs == nil {
+			return nil
+		}
+	}
+	return xs
+}
+
+func (e *Term) toNumber() interface{} {
+	if e.Type == TermTypeNumber {
+		return toNumber(e.Number)
+	}
+	return nil
 }
 
 // Unary ...
@@ -350,6 +378,14 @@ func (e *Unary) minify() {
 	e.Term.minify()
 }
 
+func (e *Unary) toNumber() interface{} {
+	v := e.Term.toNumber()
+	if v != nil && e.Op == OpSub {
+		v = funcOpNegate(v)
+	}
+	return v
+}
+
 // Pattern ...
 type Pattern struct {
 	Name   string
@@ -393,7 +429,6 @@ type PatternObject struct {
 	KeyString *String
 	KeyQuery  *Query
 	Val       *Pattern
-	KeyOnly   string
 }
 
 func (e *PatternObject) String() string {
@@ -416,9 +451,6 @@ func (e *PatternObject) writeTo(s *strings.Builder) {
 		s.WriteString(": ")
 		e.Val.writeTo(s)
 	}
-	if e.KeyOnly != "" {
-		s.WriteString(e.KeyOnly)
-	}
 }
 
 // Index ...
@@ -439,7 +471,7 @@ func (e *Index) String() string {
 func (e *Index) writeTo(s *strings.Builder) {
 	if l := s.Len(); l > 0 {
 		// ". .x" != "..x" and "0 .x" != "0.x"
-		if c := s.String()[l-1]; c == '.' || '0' <= c && c <= '9' {
+		if c := s.String()[l-1]; c == '.' || isNumber(c) {
 			s.WriteByte(' ')
 		}
 	}
@@ -450,24 +482,22 @@ func (e *Index) writeTo(s *strings.Builder) {
 func (e *Index) writeSuffixTo(s *strings.Builder) {
 	if e.Name != "" {
 		s.WriteString(e.Name)
+	} else if e.Str != nil {
+		e.Str.writeTo(s)
 	} else {
-		if e.Str != nil {
-			e.Str.writeTo(s)
-		} else {
-			s.WriteByte('[')
-			if e.IsSlice {
-				if e.Start != nil {
-					e.Start.writeTo(s)
-				}
-				s.WriteByte(':')
-				if e.End != nil {
-					e.End.writeTo(s)
-				}
-			} else {
+		s.WriteByte('[')
+		if e.IsSlice {
+			if e.Start != nil {
 				e.Start.writeTo(s)
 			}
-			s.WriteByte(']')
+			s.WriteByte(':')
+			if e.End != nil {
+				e.End.writeTo(s)
+			}
+		} else {
+			e.Start.writeTo(s)
 		}
+		s.WriteByte(']')
 	}
 }
 
@@ -483,11 +513,24 @@ func (e *Index) minify() {
 	}
 }
 
-func (e *Index) toIndices() []interface{} {
-	if e.Name == "" {
-		return nil
+func (e *Index) toIndexKey() interface{} {
+	if e.Name != "" {
+		return e.Name
+	} else if e.Str != nil {
+		if e.Str.Queries == nil {
+			return e.Str.Str
+		}
+	} else if !e.IsSlice {
+		return e.Start.toIndexKey()
+	}
+	return nil
+}
+
+func (e *Index) toIndices(xs []interface{}) []interface{} {
+	if k := e.toIndexKey(); k != nil {
+		return append(xs, k)
 	}
-	return []interface{}{e.Name}
+	return nil
 }
 
 // Func ...
@@ -543,7 +586,7 @@ func (e *String) String() string {
 
 func (e *String) writeTo(s *strings.Builder) {
 	if e.Queries == nil {
-		s.WriteString(strconv.Quote(e.Str))
+		jsonEncodeString(s, e.Str)
 		return
 	}
 	s.WriteByte('"')
@@ -599,12 +642,10 @@ func (e *Object) minify() {
 
 // ObjectKeyVal ...
 type ObjectKeyVal struct {
-	Key           string
-	KeyString     *String
-	KeyQuery      *Query
-	Val           *ObjectVal
-	KeyOnly       string
-	KeyOnlyString *String
+	Key       string
+	KeyString *String
+	KeyQuery  *Query
+	Val       *ObjectVal
 }
 
 func (e *ObjectKeyVal) String() string {
@@ -627,11 +668,6 @@ func (e *ObjectKeyVal) writeTo(s *strings.Builder) {
 		s.WriteString(": ")
 		e.Val.writeTo(s)
 	}
-	if e.KeyOnly != "" {
-		s.WriteString(e.KeyOnly)
-	} else if e.KeyOnlyString != nil {
-		e.KeyOnlyString.writeTo(s)
-	}
 }
 
 func (e *ObjectKeyVal) minify() {
@@ -643,9 +679,6 @@ func (e *ObjectKeyVal) minify() {
 	if e.Val != nil {
 		e.Val.minify()
 	}
-	if e.KeyOnlyString != nil {
-		e.KeyOnlyString.minify()
-	}
 }
 
 // ObjectVal ...
@@ -737,21 +770,21 @@ func (e *Suffix) minify() {
 	}
 }
 
-func (e *Suffix) toTerm() (*Term, bool) {
+func (e *Suffix) toTerm() *Term {
 	if e.Index != nil {
-		return &Term{Type: TermTypeIndex, Index: e.Index}, true
+		return &Term{Type: TermTypeIndex, Index: e.Index}
 	} else if e.Iter {
-		return &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{{Iter: true}}}, true
+		return &Term{Type: TermTypeIdentity, SuffixList: []*Suffix{{Iter: true}}}
 	} else {
-		return nil, false
+		return nil
 	}
 }
 
-func (e *Suffix) toIndices() []interface{} {
+func (e *Suffix) toIndices(xs []interface{}) []interface{} {
 	if e.Index == nil {
 		return nil
 	}
-	return e.Index.toIndices()
+	return e.Index.toIndices(xs)
 }
 
 // Bind ...
@@ -1005,7 +1038,7 @@ func (e *ConstTerm) writeTo(s *strings.Builder) {
 	} else if e.False {
 		s.WriteString("false")
 	} else {
-		s.WriteString(strconv.Quote(e.Str))
+		jsonEncodeString(s, e.Str)
 	}
 }
 
@@ -1015,7 +1048,7 @@ func (e *ConstTerm) toValue() interface{} {
 	} else if e.Array != nil {
 		return e.Array.toValue()
 	} else if e.Number != "" {
-		return normalizeNumber(json.Number(e.Number))
+		return toNumber(e.Number)
 	} else if e.Null {
 		return nil
 	} else if e.True {
diff --git a/query_test.go b/query_test.go
index 16bd02b..5db525e 100644
--- a/query_test.go
+++ b/query_test.go
@@ -84,7 +84,7 @@ func TestQueryRun_Errors(t *testing.T) {
 				t.Errorf("expected: %v, got: %v", expected, err)
 			}
 		} else {
-			t.Errorf("errors should occur")
+			t.Errorf("should emit an error but got: %v", v)
 		}
 		n++
 	}
@@ -114,6 +114,27 @@ func TestQueryRun_ObjectError(t *testing.T) {
 	}
 }
 
+func TestQueryRun_IndexError(t *testing.T) {
+	query, err := gojq.Parse(".foo")
+	if err != nil {
+		t.Fatal(err)
+	}
+	iter := query.Run([]interface{}{0})
+	for {
+		v, ok := iter.Next()
+		if !ok {
+			break
+		}
+		if err, ok := v.(error); ok {
+			if expected := "expected an object but got: array ([0])"; !strings.Contains(err.Error(), expected) {
+				t.Errorf("expected: %v, got: %v", expected, err)
+			}
+		} else {
+			t.Errorf("should emit an error but got: %v", v)
+		}
+	}
+}
+
 func TestQueryRun_InvalidPathError(t *testing.T) {
 	query, err := gojq.Parse(". + 1, path(. + 1)")
 	if err != nil {
@@ -135,6 +156,51 @@ func TestQueryRun_InvalidPathError(t *testing.T) {
 	}
 }
 
+func TestQueryRun_IteratorError(t *testing.T) {
+	query, err := gojq.Parse(".[]")
+	if err != nil {
+		t.Fatal(err)
+	}
+	iter := query.Run(nil)
+	for {
+		v, ok := iter.Next()
+		if !ok {
+			break
+		}
+		if err, ok := v.(error); ok {
+			if expected := "cannot iterate over: null"; err.Error() != expected {
+				t.Errorf("expected: %v, got: %v", expected, err)
+			}
+		} else {
+			t.Errorf("should emit an error but got: %v", v)
+		}
+	}
+}
+
+func TestQueryRun_Strings(t *testing.T) {
+	query, err := gojq.Parse(
+		"[\"\x00\\\\\", \"\x1f\\\"\", \"\n\\n\n\\(\"\\n\")\n\\n\", " +
+			"\"\\/\", \"\x7f\", \"\x80\", \"\\ud83d\\ude04\" | explode[]]",
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+	iter := query.Run(nil)
+	for {
+		v, ok := iter.Next()
+		if !ok {
+			break
+		}
+		if err, ok := v.(error); ok {
+			t.Fatal(err)
+		}
+		if expected := []interface{}{0x00, int('\\'), 0x1f, int('"'), int('\n'), int('\n'), int('\n'),
+			int('\n'), int('\n'), int('\n'), int('/'), 0x7f, 0xfffd, 128516}; !reflect.DeepEqual(v, expected) {
+			t.Errorf("expected: %v, got: %v", expected, v)
+		}
+	}
+}
+
 func TestQueryRun_NumericTypes(t *testing.T) {
 	query, err := gojq.Parse(".[] != 0")
 	if err != nil {
@@ -171,9 +237,12 @@ func TestQueryRun_Input(t *testing.T) {
 	if !ok {
 		t.Fatal("should emit an error but got no output")
 	}
-	err, expected := v.(error), "input(s)/0 is not allowed"
-	if got := err.Error(); got != expected {
-		t.Errorf("expected: %v, got: %v", expected, got)
+	if err, ok := v.(error); ok {
+		if expected := "input(s)/0 is not allowed"; err.Error() != expected {
+			t.Errorf("expected: %v, got: %v", expected, err)
+		}
+	} else {
+		t.Errorf("should emit an error but got: %v", v)
 	}
 }
 
diff --git a/release.go b/release.go
index 196fb77..1144485 100644
--- a/release.go
+++ b/release.go
@@ -1,5 +1,5 @@
-//go:build !debug
-// +build !debug
+//go:build !gojq_debug
+// +build !gojq_debug
 
 package gojq
 
diff --git a/scope_stack.go b/scope_stack.go
index 82d620b..e140ca1 100644
--- a/scope_stack.go
+++ b/scope_stack.go
@@ -39,11 +39,12 @@ func (s *scopeStack) empty() bool {
 	return s.index < 0
 }
 
-func (s *scopeStack) save(index, limit *int) {
-	*index, *limit = s.index, s.limit
+func (s *scopeStack) save() (index, limit int) {
+	index, limit = s.index, s.limit
 	if s.index > s.limit {
 		s.limit = s.index
 	}
+	return
 }
 
 func (s *scopeStack) restore(index, limit int) {
diff --git a/stack.go b/stack.go
index f629d28..50445fc 100644
--- a/stack.go
+++ b/stack.go
@@ -43,11 +43,12 @@ func (s *stack) empty() bool {
 	return s.index < 0
 }
 
-func (s *stack) save(index, limit *int) {
-	*index, *limit = s.index, s.limit
+func (s *stack) save() (index, limit int) {
+	index, limit = s.index, s.limit
 	if s.index > s.limit {
 		s.limit = s.index
 	}
+	return
 }
 
 func (s *stack) restore(index, limit int) {