Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bj-1line.sh
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# (C) Isaac Freeman (memotype@gmail.com). See https://github.com/memotype/bj.sh
bj()([[ $1 = - ]]||exec<<<"$1";shift;c=;rd(){ l=$c;IFS= read -rN1 c;};pr(){ printf %s "${o[@]}";};st(){ p=$1;[[ $p ]]||o=();while rd;do [[ $p&&! $q ]]&&o+=("$l");case $c in \\)rd||break;[[ $p&&$q ]]||o+=("$l${c::!p}");;\")break;;*)[[ $p ]]||o+=("$c");;esac;done;};co(){ n= b=1;while rd;do [[ $q ]]||o+=("$l");case $c in \")[[ $1||! $q ]]&&st 1||{ st;k=$(pr);};;[|{)((b++));;]|\})((--b))||{ [[ $q ]]&&exit 1;o+=("$c");break;};;:)[[ $1$b = 1&&$q&&$k = "$q" ]]&&break;;,)((0$1&&b == 1))&&{ ((n++));[[ $n = "$q" ]]&&break;};;esac;done;};for q in "$@" "";do shift&&[[ ! $q ]]&&return 2;x=0;o=();while rd;do case $c in [[:space:]])! :;;\")st;;[tfn0-9-])while o+=("$c")&&rd&&[[ $c =~ [-+.0-9Ea-z] ]];do :;done;;{)co;;[)[[ $q = 0 ]]||co 1;;*)return 2;;esac&&x=1&&break;done;done;pr;((x));)
bj()([[ $1 = - ]]||exec<<<"$1";shift;c=;r(){ l=$c;IFS= read -rN1 c;};p(){ printf %s "${o[@]}";};s(){ p=$1;[[ $p ]]||o=();while r;do [[ $p&&! $q ]]&&o+=("$l");case $c in \\)r||break;[[ $p&&$q ]]||o+=("$l${c::!p}");;\")break;;*)[[ $p ]]||o+=("$c");;esac;done;};co(){ n= b=1;while r;do [[ $q ]]||o+=("$l");case $c in \")[[ $1||! $q ]]&&s 1||{ s;k=$(p);};;[|{)((b++));;]|\})((--b))||{ [[ $q ]]&&exit 1;o+=("$c");break;};;:)[[ $1$b = 1&&$q&&$k = "$q" ]]&&break;;,)((0$1&&b==1))&&[[ $q = $((++n)) ]]&&break;;esac;done;};for q in "$@" "";do shift&&[[ ! $q ]]&&return 2;x=0;o=();while r;do case $q$c in *[[:space:]])! :;;\")s;;[tfn0-9-])while o+=("$c")&&r&&[[ $c =~ [-+.0-9Ea-z] ]];do :;done;;*{)co;;*[)[[ $q = 0 ]]||co 1;;?)return 2;;*)return 1;;esac&&x=1&&break;done;done;p;((x));)
20 changes: 10 additions & 10 deletions bj-80-col.sh
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# (C) Isaac Freeman (memotype@gmail.com). See https://github.com/memotype/bj.sh
bj()([[ $1 = - ]]||exec<<<"$1";shift;c=;rd(){ l=$c;IFS= read -rN1 c;};pr(){ \
printf %s "${o[@]}";};st(){ p=$1;[[ $p ]]||o=();while rd;do [[ $p&&! $q ]]&&o+=\
("$l");case $c in \\)rd||break;[[ $p&&$q ]]||o+=("$l${c::!p}");;\")break;;*)[[ \
$p ]]||o+=("$c");;esac;done;};co(){ n= b=1;while rd;do [[ $q ]]||o+=("$l")
case $c in \")[[ $1||! $q ]]&&st 1||{ st;k=$(pr);};;[|{)((b++));;]|\})((--b))||
{ [[ $q ]]&&exit 1;o+=("$c");break;};;:)[[ $1$b = 1&&$q&&$k = "$q" ]]&&break;;,)
((0$1&&b == 1))&&{ ((n++));[[ $n = "$q" ]]&&break;};;esac;done;};for q in "$@" \
"";do shift&&[[ ! $q ]]&&return 2;x=0;o=();while rd;do case $c in [[:space:]])
! :;;\")st;;[tfn0-9-])while o+=("$c")&&rd&&[[ $c =~ [-+.0-9Ea-z] ]];do :;done;;
{)co;;[)[[ $q = 0 ]]||co 1;;*)return 2;;esac&&x=1&&break;done;done;pr;((x));)
bj()([[ $1 = - ]]||exec<<<"$1";shift;c=;r(){ l=$c;IFS= read -rN1 c;};p(){ \
printf %s "${o[@]}";};s(){ p=$1;[[ $p ]]||o=();while r;do [[ $p&&! $q ]]&&o+=(\
"$l");case $c in \\)r||break;[[ $p&&$q ]]||o+=("$l${c::!p}");;\")break;;*)[[ \
$p ]]||o+=("$c");;esac;done;};co(){ n= b=1;while r;do [[ $q ]]||o+=("$l");case \
$c in \")[[ $1||! $q ]]&&s 1||{ s;k=$(p);};;[|{)((b++));;]|\})((--b))||{ [[ $q \
]]&&exit 1;o+=("$c");break;};;:)[[ $1$b = 1&&$q&&$k = "$q" ]]&&break;;,)((0$1&&
b==1))&&[[ $q = $((++n)) ]]&&break;;esac;done;};for q in "$@" "";do shift&&[[ \
! $q ]]&&return 2;x=0;o=();while r;do case $q$c in *[[:space:]])! :;;\")s;;
[tfn0-9-])while o+=("$c")&&r&&[[ $c =~ [-+.0-9Ea-z] ]];do :;done;;*{)co;;*[)[[ \
$q = 0 ]]||co 1;;?)return 2;;*)return 1;;esac&&x=1&&break;done;done;p;((x));)
18 changes: 9 additions & 9 deletions bj-90-col.sh
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# (C) Isaac Freeman (memotype@gmail.com). See https://github.com/memotype/bj.sh
bj()([[ $1 = - ]]||exec<<<"$1";shift;c=;rd(){ l=$c;IFS= read -rN1 c;};pr(){ printf %s \
"${o[@]}";};st(){ p=$1;[[ $p ]]||o=();while rd;do [[ $p&&! $q ]]&&o+=("$l");case $c in \\)
rd||break;[[ $p&&$q ]]||o+=("$l${c::!p}");;\")break;;*)[[ $p ]]||o+=("$c");;esac;done;}
co(){ n= b=1;while rd;do [[ $q ]]||o+=("$l");case $c in \")[[ $1||! $q ]]&&st 1||{ st;k\
=$(pr);};;[|{)((b++));;]|\})((--b))||{ [[ $q ]]&&exit 1;o+=("$c");break;};;:)[[ $1$b = 1&&
$q&&$k = "$q" ]]&&break;;,)((0$1&&b == 1))&&{ ((n++));[[ $n = "$q" ]]&&break;};;esac;done
};for q in "$@" "";do shift&&[[ ! $q ]]&&return 2;x=0;o=();while rd;do case $c in \
[[:space:]])! :;;\")st;;[tfn0-9-])while o+=("$c")&&rd&&[[ $c =~ [-+.0-9Ea-z] ]];do :;done
;;{)co;;[)[[ $q = 0 ]]||co 1;;*)return 2;;esac&&x=1&&break;done;done;pr;((x));)
bj()([[ $1 = - ]]||exec<<<"$1";shift;c=;r(){ l=$c;IFS= read -rN1 c;};p(){ printf %s \
"${o[@]}";};s(){ p=$1;[[ $p ]]||o=();while r;do [[ $p&&! $q ]]&&o+=("$l");case $c in \\)r\
||break;[[ $p&&$q ]]||o+=("$l${c::!p}");;\")break;;*)[[ $p ]]||o+=("$c");;esac;done;};co\
(){ n= b=1;while r;do [[ $q ]]||o+=("$l");case $c in \")[[ $1||! $q ]]&&s 1||{ s;k=$(p);}
;;[|{)((b++));;]|\})((--b))||{ [[ $q ]]&&exit 1;o+=("$c");break;};;:)[[ $1$b = 1&&$q&&$k \
= "$q" ]]&&break;;,)((0$1&&b==1))&&[[ $q = $((++n)) ]]&&break;;esac;done;};for q in "$@" \
"";do shift&&[[ ! $q ]]&&return 2;x=0;o=();while r;do case $q$c in *[[:space:]])! :;;\")s
;;[tfn0-9-])while o+=("$c")&&r&&[[ $c =~ [-+.0-9Ea-z] ]];do :;done;;*{)co;;*[)[[ $q = 0 \
]]||co 1;;?)return 2;;*)return 1;;esac&&x=1&&break;done;done;p;((x));)
47 changes: 24 additions & 23 deletions bj.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,30 @@ bj() (
c=

# Read a character
rd() {
r() {
l=$c
IFS= read -rN1 c
}

# Join the characters in the $o array
pr() {
p() {
# Using ':' with arguments is nice for 'bash -x' debugging
: : "=== pr()"
: : "=== p()"
printf %s "${o[@]}"
}


# Scan strings, saving to $o unless navigation only needs to skip them.
st() {
: : "=== st()"
s() {
: : "=== s()"
p=$1
[[ $p ]] || o=()
while rd; do
while r; do
: : "--- lc=$l$c="
[[ $p && ! $q ]] && o+=("$l")
case $c in
\\)
rd || break
r || break
# Skip while navigating. Otherwise include $c only when capturing.
[[ $p && $q ]] || o+=("$l${c::!p}")
;;
Expand All @@ -55,11 +55,11 @@ bj() (
co() {
: : "=== co()"
n= b=1
while rd; do
while r; do
: : "--- l=$l= c=$c= q=$q= b=$b= ---"
[[ $q ]] || o+=("$l")
case $c in
\") [[ $1 || ! $q ]] && st 1 || { st; k=$(pr); } ;;
\") [[ $1 || ! $q ]] && s 1 || { s; k=$(p); } ;;
[|{) ((b++)) ;; # ]) <- fix vim syntax
]|\})
((--b)) || {
Expand All @@ -73,10 +73,9 @@ bj() (
# Found the key, just stop and let the main loop parse from here.
:) [[ $1$b = 1 && $q && $k = "$q" ]] && break ;;
,)
((0$1 && b == 1)) && {
((n++))
[[ $n = "$q" ]] && break
}
((0$1 && b==1)) \
&& [[ $q = $((++n)) ]] \
&& break
;;
esac
done
Expand All @@ -89,26 +88,28 @@ bj() (
x=0
: : "--- q=$q"
o=()
while rd; do
while r; do
: : "mn --- l=$l c=$c"
case $c in
[[:space:]]) ! : ;;
\") st ;;
# Prefix with $q so scalar cases only match during final output.
case $q$c in
*[[:space:]]) ! : ;;
\") s ;;
[tfn0-9-])
while o+=("$c") \
&& rd \
&& [[ $c =~ [-+.0-9Ea-z] ]]
&& r \
&& [[ $c =~ [-+.0-9Ea-z] ]]
do :;done
;;
{) co ;;
[) [[ $q = 0 ]] || co 1 ;; #])
*) return 2 ;;
*{) co ;;
*[) [[ $q = 0 ]] || co 1 ;; #])
?) return 2 ;;
*) return 1 ;;
esac && x=1 && break
done
done

# Print whatever we last stored in $o
pr
p

((x))
)
Expand Down
27 changes: 27 additions & 0 deletions test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,22 @@ runtest top '{"target":"top","outer":{"target":"nested"}}' target
runtest direct \
'{"level":{"child":{"target":"nested"},"target":"direct"}}' level target

# Traversal must stop when a selected value is a scalar.
runteststatus 1 '' '{"a":"x","b":"y"}' a extra
runteststatus 1 '' '{"b":"y","a":"x"}' a extra
runteststatus 1 '' '{"a":1,"b":2}' a extra
runteststatus 1 '' '{"b":2,"a":1}' a extra
runteststatus 1 '' '{"a":true,"b":false}' a extra
runteststatus 1 '' '{"b":false,"a":true}' a extra
runteststatus 1 '' '{"a":false,"b":true}' a extra
runteststatus 1 '' '{"b":true,"a":false}' a extra
runteststatus 1 '' '{"a":null,"b":0}' a extra
runteststatus 1 '' '{"b":0,"a":null}' a extra
runteststatus 1 '' '[1,2]' 0 extra
runteststatus 1 '' '[1,2]' 1 extra
runteststatus 1 '' '{"outer":{"a":1,"b":2}}' outer a extra
runteststatus 1 '' '{"a":1,"b":2}' a extra more

# Numbers tests
runtest "4.2e10" '[0, -1, 4.2e10]' 2
runtest "-1" '[0, -1, 4.2e10]' 1
Expand Down Expand Up @@ -230,6 +246,17 @@ runtest hit \
'[0,1,2,3,4,5,6,7,8,9,{"result":"hit"}]' 10 result
runtest hit '[{},[],{"result":"hit"}]' 2 result

# Empty caller query terms are unsupported and fail when reached.
runteststatus 2 '' '{"":42}' ''
runteststatus 2 '' '{"outer":{"":"value"}}' outer ''
runteststatus 2 '' '{"outer":{"leaf":1}}' '' outer
runteststatus 2 '' '{"outer":{"leaf":1}}' outer '' leaf
runteststatus 2 '' '{"outer":{"leaf":1}}' outer leaf ''
runteststatus 1 '' '{"outer":{"leaf":1}}' missing ''
runtest 7 '{"":42,"normal":7}' normal
runtest '{"":42}' '{"":42}'
runtest '' '{"value":""}' value

# Representative Kubernetes-shaped data used by build and shell automation
kubernetes_json='{"items":[{"metadata":{"name":"api","annotations":{"example.com/config":"line1\nline2"}},"spec":{"nodeName":null,"containers":[{"name":"app","env":[{"name":"MODE","value":""}]}]}}]}'
runtest api "$kubernetes_json" items 0 metadata name
Expand Down