summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2024-05-22 16:17:05 -0400
committerLuke T. Shumaker <lukeshu@lukeshu.com>2024-05-22 16:17:05 -0400
commit7c67b09765d7334690d9b48e91ee188e9be179b7 (patch)
tree692ed4aeb0c6034c0ee78e23119028a4417e4446
parenta23ae9818310834f54a500c0e583c3652395f0da (diff)
have a single token callback
-rwxr-xr-xgron63
-rw-r--r--json.sh59
-rwxr-xr-xtokenize10
-rwxr-xr-xtrace30
4 files changed, 110 insertions, 52 deletions
diff --git a/gron b/gron
new file mode 100755
index 0000000..0fd05d0
--- /dev/null
+++ b/gron
@@ -0,0 +1,63 @@
+#!/bin/bash
+set -e
+
+. "$(dirname -- "${BASH_SOURCE[0]}")/json.sh"
+
+stack=()
+
+print_lhs() {
+ printf 'json'
+ local x
+ for x in "${stack[@]}"; do
+ printf '[%s]' "$x"
+ done
+ printf '='
+}
+
+handle_token() {
+ local val=''
+ case "$1" in
+ object_beg)
+ val='{}'
+ stack+=('bogus')
+ ;;
+ object_end)
+ stack=("${stack[@]::${#stack[@]}-1}")
+ ;;
+ object_key)
+ stack[${#stack[@]}-1]="${2@Q}"
+ ;;
+ array_beg)
+ val='[]'
+ stack+=('0')
+ ;;
+ array_end)
+ stack=("${stack[@]::${#stack[@]}-1}")
+ ;;
+ number)
+ val="$2"
+ ;;
+ string)
+ val="${2@Q}"
+ ;;
+ null|true|false)
+ val="$1"
+ ;;
+ error)
+ printf >&2 "json error: $1\n" "${@:2}"
+ ;;
+ esac
+ if [[ -n "$val" ]]; then
+ printf 'json'
+ local x
+ for x in "${stack[@]}"; do
+ printf '[%s]' "$x"
+ done
+ printf '=%s;\n' "$val"
+ fi
+ if [[ ${#stack[@]} -gt 0 && ${stack[${#stack[@]}-1]} =~ ^[0-9]$ ]]; then
+ stack[${#stack[@]}-1]=$((${stack[${#stack[@]}-1]}+1))
+ fi
+}
+
+json_tokenize handle_token
diff --git a/json.sh b/json.sh
index 9d7701b..a197158 100644
--- a/json.sh
+++ b/json.sh
@@ -1,11 +1,30 @@
#!/hint/bash
-json_parse() {
- type json_object_beg &>/dev/null || json_object_beg() { :; } # no args
- type json_object_end &>/dev/null || json_object_end() { :; } # no args
- type json_array_beg &>/dev/null || json_array_beg() { :; } # no args
- type json_array_end &>/dev/null || json_array_end() { :; } # no args
- type json_atom &>/dev/null || json_atom() { :; } # $1=(key|string|number|bool|null) $2=$val
+# Usage: json_tokenize myfn <input
+#
+# Call `myfn` repeatedly with any of the following values:
+#
+# myfn object_beg
+# myfn object_key $val
+# myfn object_end
+#
+# myfn array_beg
+# myfn array_end
+#
+# myfn number $val
+# myfn string $val
+# myfn null
+# myfn true
+# myfn false
+#
+# myfn error $format $args...
+#
+# Assumptions:
+# - `set -e`
+# - Input is valid UTF-8
+# - LC_* is set to a UTF-8 value
+json_tokenize() {
+ local _json_token=$1
local _json_buf
_json_buf="$(cat)"
@@ -17,7 +36,7 @@ json_parse() {
}
_json_error() {
- printf >&2 "json error: $1"'\n' "${@:2}"
+ "$_json_token" "$@"
return 1
}
@@ -50,13 +69,13 @@ _json_value() {
_json_object() {
_json_expect '{'
- json_object_beg
+ "$_json_token" object_beg
_json_ws
case "${_json_buf::1}" in
'"' )
local _json_obj_key
while true; do
- _json_string key
+ _json_string object_key
_json_ws
_json_expect ':'
_json_value
@@ -68,7 +87,7 @@ _json_object() {
;;
'}' )
_json_buf=${_json_buf:1}
- json_object_end
+ "$_json_token" object_end
return
;;
esac
@@ -76,7 +95,7 @@ _json_object() {
;;
'}' )
_json_buf=${_json_buf:1}
- json_object_end
+ "$_json_token" object_end
return
;;
esac
@@ -84,11 +103,11 @@ _json_object() {
_json_array() {
_json_expect '['
- json_array_beg
+ "$_json_token" array_beg
_json_ws
if [[ "${_json_buf::1}" == ']' ]]; then
_json_buf=${_json_buf:1}
- json_array_end
+ "$_json_token" array_end
return
fi
while true; do
@@ -101,7 +120,7 @@ _json_array() {
;;
']' )
_json_buf=${_json_buf:1}
- json_array_end
+ "$_json_token" array_end
return
;;
esac
@@ -113,7 +132,7 @@ _json_string() {
_json_expect '"'
local _json_strval=''
local _json_re='^[^\"]+'
- local _json_c json_n _json_n2
+ local _json_c _json_n _json_n2
while true; do
case "${_json_buf::1}" in
"\\" )
@@ -154,7 +173,7 @@ _json_string() {
;;
'"' )
_json_buf=${_json_buf:1}
- json_atom "$1" "$_json_strval"
+ "$_json_token" "$1" "$_json_strval"
return
;;
* )
@@ -174,7 +193,7 @@ _json_number() {
_json_error 'invalid number: %q' "${_json_buf::16}"
fi
_json_buf=${_json_buf:${#BASH_REMATCH[0]}}
- json_atom number "${BASH_REMATCH[0]}"
+ "$_json_token" number "${BASH_REMATCH[0]}"
}
_json_lit() {
@@ -182,9 +201,5 @@ _json_lit() {
_json_error 'expected %q, got: %q' "$1" "${_json_buf::${#1}}"
fi
_json_buf=${_json_buf:${#1}}
- if [[ "$1" == 'null' ]]; then
- json_atom null null
- else
- json_atom bool "$1"
- fi
+ "$_json_token" "$1"
}
diff --git a/tokenize b/tokenize
new file mode 100755
index 0000000..35576af
--- /dev/null
+++ b/tokenize
@@ -0,0 +1,10 @@
+#!/bin/bash
+set -e
+
+. "$(dirname -- "${BASH_SOURCE[0]}")/json.sh"
+
+handle_token() {
+ printf '%s\n' "${*@Q}"
+}
+
+json_tokenize handle_token
diff --git a/trace b/trace
deleted file mode 100755
index 3aa657d..0000000
--- a/trace
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/bash
-
-# no args
-json_object_beg() {
- echo json_object_beg
-}
-
-# no args
-json_object_end() {
- echo json_object_end
-}
-
-# no args
-json_array_beg() {
- echo json_array_beg
-}
-
-# no args
-json_array_end() {
- echo json_array_end
-}
-
-# $1=(key|string|number|bool|null) $2=$val
-json_atom() {
- printf 'json_atom %q %q\n' "$1" "$2"
-}
-
-. "$(dirname -- "${BASH_SOURCE[0]}")/json.sh"
-
-json_parse