Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

it's a JSON parser written in bash!

  • Loading branch information...
commit f1c2064db1801968a6791e2d65d1cf485ee239ca 0 parents
@dominictarr authored
Showing with 364 additions and 0 deletions.
  1. +3 −0  .gitignore
  2. +32 −0 all-tests.sh
  3. +6 −0 bin/json_parse
  4. +1 −0  errlog
  5. 0  outlog
  6. +14 −0 package.json
  7. +93 −0 parse.sh
  8. +25 −0 readme.markdown
  9. +10 −0 test/.generate-valid
  10. +1 −0  test/errlog
  11. +33 −0 test/invalid-test.sh
  12. +1 −0  test/invalid/comma.json
  13. +3 −0  test/invalid/comma_obj.json
  14. +1 −0  test/invalid/unclosed_array.json
  15. +2 −0  test/invalid/unclosed_object.json
  16. 0  test/out
  17. +1 −0  test/outlog
  18. +12 −0 test/parse-test.sh
  19. +40 −0 test/tokenizer-test.sh
  20. +34 −0 test/valid-test.sh
  21. +1 −0  test/valid/array.json
  22. +5 −0 test/valid/array.parsed
  23. +1 −0  test/valid/empty_array.json
  24. +1 −0  test/valid/empty_array.parsed
  25. +1 −0  test/valid/empty_object.json
  26. +1 −0  test/valid/empty_object.parsed
  27. +4 −0 test/valid/many_object.json
  28. +3 −0  test/valid/many_object.parsed
  29. +5 −0 test/valid/nested_array.json
  30. +9 −0 test/valid/nested_array.parsed
  31. +7 −0 test/valid/nested_object.json
  32. +5 −0 test/valid/nested_object.parsed
  33. +1 −0  test/valid/number.json
  34. +1 −0  test/valid/number.parsed
  35. +3 −0  test/valid/object.json
  36. +2 −0  test/valid/object.parsed
  37. +1 −0  test/valid/string.json
  38. +1 −0  test/valid/string.parsed
3  .gitignore
@@ -0,0 +1,3 @@
+node_modules
+node_modules/*
+npm_debug.log
32 all-tests.sh
@@ -0,0 +1,32 @@
+#! /usr/bin/env bash
+
+__filename=`readlink -f $0`
+__dirname=`dirname $__filename`
+cd $__dirname
+
+#set -e
+fail=0
+tests=0
+#all_tests=${__dirname:}
+#echo PLAN ${#all_tests}
+for test in test/*.sh ;
+do
+ let tests=$tests+1
+ echo TEST: $test
+ bash $test
+ ret=$?
+ if [ $ret -eq 0 ] ; then
+ echo OK: ---- $test
+ let passed=$passed+1
+ else
+ echo FAIL: $test $fail
+ let fail=$fail+$ret
+ fi
+done
+
+if [ $fail -eq 0 ]; then
+ echo -n 'SUCCESS '
+else
+ echo -n 'FAILOUR '
+fi
+echo $passed / $tests
6 bin/json_parse
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+
+#add this feature to require...
+__filename=`readlink -f $0`
+. `dirname $__filename`/../parse.sh
+tokenize | parse
1  errlog
@@ -0,0 +1 @@
+/home/dominic/dev/JSON.sh/test/invalid-test.sh: line 10: ../bin/json_parse: No such file or directory
0  outlog
No changes.
14 package.json
@@ -0,0 +1,14 @@
+{ "name": "JSON.sh"
+, "version": "0.0.0"
+, "description": ""
+, "homepage": "http://github.com/dominictarr/JSON-sh"
+, "repository":
+ { "type": "git"
+ , "url": "https://github.com/dominictarr/JSON-sh.git" }
+, "bin": {
+ "json_parse": "./bin/json_parse"
+ }
+, "dependencies": {}
+, "devDependencies": {}
+, "author": "Dominic Tarr <dominic.tarr@gmail.com> (http://bit.ly/dominictarr)"
+, "scripts": { "test": "./all-tests.sh" } }
93 parse.sh
@@ -0,0 +1,93 @@
+
+throw () {
+ echo $* >&2
+ exit 1
+}
+
+tokenize () {
+ egrep -ao '[]|[{}]|:|,|("((\\")|[^"])*")|:|(\-?[0-9]*\.?([0-9]*)?(e?\-?([0-9]*))?)|null|true|false' --color=never
+}
+
+parse_array () {
+ local index=0
+ local ary=''
+ read token
+ while true;
+ do
+ key=$index
+ case "$token" in
+ ']') break ;;
+ *)
+ parse_value "$1" "$index"
+ let index=$index+1
+ ary="$ary""$value"
+ read token
+ case "$token" in
+ ']') break ;;
+ ',') ary="$ary", ;;
+ *)
+ if [ "_$token" = _ ]; then token=EOF; fi
+ throw "EXPECTED ] or , GOT $token"
+ ;;
+ esac
+ read token
+ ;;
+ esac
+ done
+ value=`printf '[%s]' $ary`
+}
+
+parse_object () {
+ local go=true
+ local obj=''
+ local EXPECT_COMMA=0
+ local EXPECT_COLON=0
+ read token
+ while [ "$go" = true ];
+ do
+ case "$token" in
+ '}') break ;;
+ *)
+
+ key=$token
+ read colon
+ if [ "$colon" != ':' ]; then throw "EXPECTED COLON, GOT $colon"; fi
+ if [ "_$key" = _ ]; then throw "NULL KEY"; fi
+ read token
+ parse_value "$1" "$key"
+ obj="$obj$key:$value"
+
+ read token
+ case "$token" in
+ '}') break;;
+ ,) obj="$obj,"; read token ;;
+ *)
+ if [ "_$token" = _ ]; then token=EOF; fi
+ throw "EXPECTED , or }, but got $token"
+ ;;
+ esac
+ ;;
+ esac
+ done
+ value=`printf '{%s}' "$obj"`
+}
+
+parse_value () {
+ local jpath
+
+ if [ "x$1" = "x" ]; then jpath="$2"; else jpath="$1,$2"; fi
+
+ case "$token" in
+ {) parse_object "$jpath" ;;
+ [) parse_array "$jpath" ;;
+ ','|'}'|']') throw "EXPECTED value, GOT $token" ;;
+ *) value=$token
+ ;;
+ esac
+ printf "[%s]\t%s\n" "$jpath" "$value"
+}
+
+parse () {
+ read token
+ parse_value
+}
25 readme.markdown
@@ -0,0 +1,25 @@
+# JSON.sh
+
+yo, so it's a json parser written in bash
+
+this is what the interface in gonna be:
+
+``` bash
+cat package.json | JSONsh '.dependencies'
+
+#key value
+foo ~1
+```
+
+or a more complex example:
+
+``` bash
+curl registry.npmjs.org/module : JSONsh '.versions[*]'
+
+#key value
+0.0.0 {...}
+
+```
+
+
+curl registry.npmjs.org/assertions | ./bin/json_parse | egrep '\["versions","[^"]*"\]'
10 test/.generate-valid
@@ -0,0 +1,10 @@
+echo "set -e"
+for input in valid/*.json
+do
+expected=${input%.json}.parsed
+cat $input | ../bin/json_parse > $expected
+echo "# $input"
+echo "diff <(cat $input | ../bin/json_parse) ${input%.json}.parsed"
+echo "echo OK $input"
+
+done
1  test/errlog
@@ -0,0 +1 @@
+EXPECTED , or }, but got EOF
33 test/invalid-test.sh
@@ -0,0 +1,33 @@
+#! /usr/bin/env bash
+
+__filename=`readlink -f $0`
+__dirname=`dirname $__filename`
+cd $__dirname
+
+echo _=$_
+echo 0=$0
+echo __filename=$__filename
+echo __dirname=$__dirname
+echo PWD=$PWD
+#env
+fails=0
+for input in invalid/*
+do
+ cat $input | ../bin/json_parse > outlog 2> errlog
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "NOT OK: cat $input | ../bin/json_parse SHOULD FAIL"
+ echo "OUTPUT WAS >>>"
+ cat outlog
+ echo "<<<"
+ let fails=$fails+1
+ else
+ echo "OK: cat $input | ../bin/json_parse failed correctly"
+ echo "stderr was >>>"
+ cat errlog
+ echo "<<<"
+ fi
+
+done
+echo "$fails test(s) failed"
+exit $fails
1  test/invalid/comma.json
@@ -0,0 +1 @@
+[,]
3  test/invalid/comma_obj.json
@@ -0,0 +1,3 @@
+{
+ "hello", "comma!"
+}
1  test/invalid/unclosed_array.json
@@ -0,0 +1 @@
+[5,4,"goeu"
2  test/invalid/unclosed_object.json
@@ -0,0 +1,2 @@
+{
+ "hELLO": "goodeoeu"
0  test/out
No changes.
1  test/outlog
@@ -0,0 +1 @@
+["hELLO"] "goodeoeu"
12 test/parse-test.sh
@@ -0,0 +1,12 @@
+
+__filename=`readlink -f $0`
+__dirname=`dirname $__filename`
+cd $__dirname
+
+. ../parse.sh
+
+cat ../package.json | tokenize | parse
+
+#echo '"oooo" ' | tokenize | parse
+echo '[true, 1, [0, {}]] ' | tokenize | parse
+echo '{"true": 1}' | tokenize | parse
40 test/tokenizer-test.sh
@@ -0,0 +1,40 @@
+#! /usr/bin/env bash
+
+__filename=`readlink -f $0`
+__dirname=`dirname $__filename`
+cd $__dirname
+
+. $__dirname/../parse.sh
+set -e
+
+diff <( echo '"dah"' | tokenize ) <( echo '"dah"' )
+diff <( echo '""' | tokenize ) <( echo '""' )
+diff <( echo '["dah"]' | tokenize ) <( printf '[\n\"dah\"\n]\n' )
+diff <( echo '" "' | tokenize ) <( printf '" "\n' )
+diff <( printf '" \\" "' | tokenize ) <( printf '" \\" "\n' )
+
+diff \
+<( echo '["dah"]' | tokenize ) \
+<( echo \
+'[
+"dah"
+]')
+
+diff <( echo '123' | tokenize ) <( echo '123' )
+diff <( echo '123.142' | tokenize ) <( echo '123.142' )
+diff <( echo '-123' | tokenize ) <( echo '-123')
+
+#diff <( echo '1e23' | tokenize ) <( printf '1e23\n' )
+diff <( echo '0.1' | tokenize ) <( echo '0.1' )
+diff <( echo '-110' | tokenize ) <( echo '-110' )
+diff <( echo '-110.10' | tokenize ) <( echo '-110.10' )
+diff <( echo '-110e10' | tokenize ) <( echo '-110e10' )
+diff <( echo 'null' | tokenize ) <( echo 'null' )
+diff <( echo 'true' | tokenize ) <( echo 'true' )
+diff <( echo 'false' | tokenize ) <( echo 'false' )
+diff <( echo '[ null , -110e10, "null" ]' \
+ | tokenize ) <( printf '[\nnull\n,\n-110e10\n,\n"null"\n]\n' )
+diff <( echo '{"e": false}' | tokenize ) <( printf '{\n"e"\n:\nfalse\n}\n' )
+diff <( echo '{"e": "string"}' | tokenize ) <( printf '{\n"e"\n:\n"string"\n}\n' )
+
+cat ../package.json | tokenize
34 test/valid-test.sh
@@ -0,0 +1,34 @@
+
+__filename=`readlink -f $0`
+__dirname=`dirname $__filename`
+
+cd $__dirname
+
+set -e
+# valid/array.json
+diff <(cat valid/array.json | ../bin/json_parse) valid/array.parsed
+echo OK valid/array.json
+# valid/empty_array.json
+diff <(cat valid/empty_array.json | ../bin/json_parse) valid/empty_array.parsed
+echo OK valid/empty_array.json
+# valid/empty_object.json
+diff <(cat valid/empty_object.json | ../bin/json_parse) valid/empty_object.parsed
+echo OK valid/empty_object.json
+# valid/many_object.json
+diff <(cat valid/many_object.json | ../bin/json_parse) valid/many_object.parsed
+echo OK valid/many_object.json
+# valid/nested_array.json
+diff <(cat valid/nested_array.json | ../bin/json_parse) valid/nested_array.parsed
+echo OK valid/nested_array.json
+# valid/nested_object.json
+diff <(cat valid/nested_object.json | ../bin/json_parse) valid/nested_object.parsed
+echo OK valid/nested_object.json
+# valid/number.json
+diff <(cat valid/number.json | ../bin/json_parse) valid/number.parsed
+echo OK valid/number.json
+# valid/object.json
+diff <(cat valid/object.json | ../bin/json_parse) valid/object.parsed
+echo OK valid/object.json
+# valid/string.json
+diff <(cat valid/string.json | ../bin/json_parse) valid/string.parsed
+echo OK valid/string.json
1  test/valid/array.json
@@ -0,0 +1 @@
+[1,2,3,"hello"]
5 test/valid/array.parsed
@@ -0,0 +1,5 @@
+[0] 1
+[1] 2
+[2] 3
+[3] "hello"
+[] [1,2,3,"hello"]
1  test/valid/empty_array.json
@@ -0,0 +1 @@
+[]
1  test/valid/empty_array.parsed
@@ -0,0 +1 @@
+[] []
1  test/valid/empty_object.json
@@ -0,0 +1 @@
+{}
1  test/valid/empty_object.parsed
@@ -0,0 +1 @@
+[] {}
4 test/valid/many_object.json
@@ -0,0 +1,4 @@
+{
+ "key1": "string",
+ "key2": 3573
+}
3  test/valid/many_object.parsed
@@ -0,0 +1,3 @@
+["key1"] "string"
+["key2"] 3573
+[] {"key1":"string","key2":3573}
5 test/valid/nested_array.json
@@ -0,0 +1,5 @@
+[ 1
+, []
+, [4, "hello", {}]
+, {"array": []}
+]
9 test/valid/nested_array.parsed
@@ -0,0 +1,9 @@
+[0] 1
+[1] []
+[2,0] 4
+[2,1] "hello"
+[2,2] {}
+[2] [4,"hello",{}]
+[3,"array"] []
+[3] {0:[]}
+[] [1,[],[4,"hello",{}],{0:[]}]
7 test/valid/nested_object.json
@@ -0,0 +1,7 @@
+{
+ "object": {
+ "key": "value",
+ "empty": {}
+ },
+ "number": 5
+}
5 test/valid/nested_object.parsed
@@ -0,0 +1,5 @@
+["object","key"] "value"
+["object","empty"] {}
+["object"] {"key":"value","empty":{}}
+["number"] 5
+[] {"empty":{"key":"value","empty":{}},"number":5}
1  test/valid/number.json
@@ -0,0 +1 @@
+3
1  test/valid/number.parsed
@@ -0,0 +1 @@
+[] 3
3  test/valid/object.json
@@ -0,0 +1,3 @@
+{
+ "key": "Value"
+}
2  test/valid/object.parsed
@@ -0,0 +1,2 @@
+["key"] "Value"
+[] {"key":"Value"}
1  test/valid/string.json
@@ -0,0 +1 @@
+"hello this is a string"
1  test/valid/string.parsed
@@ -0,0 +1 @@
+[] "hello this is a string"
Please sign in to comment.
Something went wrong with that request. Please try again.