Golang implementation of jq: gojq

I have been working on a pure Go language implementation of jq. The command gojq is highly compatible with jq and also capable to be embeded within Go products. Creating a cli tool in Go language is much fun and learned various things about jq.

 % jq -n '(1, 2) * (3, 4)'
3
6
4
8
% jq -n -c '[range(1;5) * range(1;5)]'
[1,2,3,4,2,4,6,8,3,6,9,12,4,8,12,16]
% jq -n -c 'def f: 1, f; [limit(10; f)]'
[1,1,1,1,1,1,1,1,1,1]
% jq -n -c '[[0,1] | while(.[0]<100; [.[1], .[0]+.[1]]) | .[0]]'
[0,1,1,2,3,5,8,13,21,34,55,89]
 % echo '[1,2]' | jq 'def f(a; b): a * 10 + b; f(.[]; .[])'
11
21
12
22
% jq -n -c 'def f($n): if $n == 0 then empty else $n, f($n - 1) end; [f(10)]'
[10,9,8,7,6,5,4,3,2,1]
 % echo '1 2 3' | jq 'def ntimes($n): . * $n; ntimes(3)'
3
6
9
% echo '[1, 3, 6]' | jq 'def mean: add / length; mean'
3.3333333333333335
def map(f): [.[] | f];def select(f): if f then . else empty end;
def recurse: recurse(.[]?);
def recurse(f): def r: ., (f | r); r;
func unitIterator(v interface{}) <-chan interface{} {
c := make(chan interface{}, 1)
defer func() {
defer close(c)
c <- v
}()
return c
}
func binopIterator(l <-chan interface{}, r <-chan interface{}, fn func(l, r interface{}) interface{}) <-chan interface{} {
d := make(chan interface{}, 1)
go func() {
defer close(d)
ls := reuseIterator(l)
for r := range r {
for l := range ls() {
d <- fn(l, r)
}
}
}()
return d
}
def range($n): 0 | while(. < $n; . + 1);def while(cond; update):
def _while: if cond then ., (update | _while) else empty end;
_while;
0: push 1
1: push 2
2: call multiply
3: push 3
4: push 4
5: call multiply
6: call add
7: ret
[]
[ 1 ] # 0: push 1
[ 1, 2 ] # 1: push 2
[ 2 ] # 2: call multiply
[ 2, 3 ] # 3: push 3
[ 2, 3, 4 ] # 4: push 4
[ 2, 12 ] # 5: call multiply
[ 14 ] # 6: call add
[] # 7: ret => output: 14
0: fork 3
1: push 3
2: jump 4
3: push 4
4: fork 7
5: push 1
6: jump 8
7: push 2
8: call multiply
9: ret
[]
[] # 0: fork 3 => forks: [ (3, []) ]
[ 3 ] # 1: push 3
[ 3 ] # 2: jump 4
[ 3 ] # 4: fork 7 => forks: [ (3, []), (7, [3]) ]
[ 3, 1 ] # 5: push 1
[ 3, 1 ] # 6: jump 8
[ 3 ] # 8: call multiply
[] # 9: ret => output: 3
[ 3 ] # backtrack => restore stack ([3]) and pc (7), forks: [ (3, []) ]
[ 3, 2 ] # 7: push 2
[ 6 ] # 8: call multiply
[] # 9: ret => output: 6
[] # backtrack => restore stack ([]) and pc (3), forks: []
[ 4 ] # 3: push 4
[ 4 ] # 4: fork 7 => forks: [ (7, [4]) ]
[ 4, 1 ] # 5: push 1
[ 4, 1 ] # 6: jump 8
[ 4 ] # 8: call multiply
[] # 9: ret => output: 4
[ 4 ] # backtrack => restore stack ([4]) and pc (7), forks: []
[ 4, 2 ] # 7: push 2
[ 8 ] # 8: call multiply
[] # 9: ret => output: 8
[] # backtrack => no forks, terminate
 % echo '{"foo": 4722366482869645213696}' | gojq .foo
4722366482869645213696
% gojq -n '123456789 * 987654321'
121932631112635269
% gojq -n '123456789123456789 * 987654321987654321'
121932631356500531347203169112635269
% gojq -n '987654321987654321 % 123456789123456789'
9000000009
% gojq -n -r 'def fact($n): if $n < 1 then 1 else $n * fact($n - 1) end; range(40;51) | "\(.)! = \(fact(.))"'
40! = 815915283247897734345611269596115894272000000000
41! = 33452526613163807108170062053440751665152000000000
42! = 1405006117752879898543142606244511569936384000000000
43! = 60415263063373835637355132068513997507264512000000000
44! = 2658271574788448768043625811014615890319638528000000000
45! = 119622220865480194561963161495657715064383733760000000000
46! = 5502622159812088949850305428800254892961651752960000000000
47! = 258623241511168180642964355153611979969197632389120000000000
48! = 12413915592536072670862289047373375038521486354677760000000000
49! = 608281864034267560872252163321295376887552831379210240000000000
50! = 30414093201713378043612608166064768844377641568960512000000000000
 % gojq -n 'def fact($n): if $n < 1 then 1 else $n * fact($n - 1) end;
fact(100) | tostring | explode | map(. - 48) | add'
 % gojq --yaml-input --yaml-output ".services.app.volumes" docker-compose.yml
- .:/app
 % echo '{"x":"foo","y":[0,"foo"],"z":{"w":"foofoo","q":"baz"}}' | \
jq '(.. | strings) |= sub("foo"; "bar"; "g")'
{
"x": "bar",
"y": [
0,
"bar"
],
"z": {
"w": "barbar",
"q": "baz"
}
}

A programmer who loves programming languages.