diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-05-22 16:17:05 -0400 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-05-22 16:17:05 -0400 |
commit | 7c67b09765d7334690d9b48e91ee188e9be179b7 (patch) | |
tree | 692ed4aeb0c6034c0ee78e23119028a4417e4446 | |
parent | a23ae9818310834f54a500c0e583c3652395f0da (diff) |
have a single token callback
-rwxr-xr-x | gron | 63 | ||||
-rw-r--r-- | json.sh | 59 | ||||
-rwxr-xr-x | tokenize | 10 | ||||
-rwxr-xr-x | trace | 30 |
4 files changed, 110 insertions, 52 deletions
@@ -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 @@ -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 @@ -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 |