├── README.md ├── jp ├── macros.jp ├── test-bootstrap.bash └── tests ├── parse ├── array.bash ├── halts.bash ├── json-test-suite.bash ├── null.bash └── string-unicode.bash ├── print ├── indent.bash ├── plain.bash ├── pretty.bash └── silent.bash ├── share ├── JSONTestSuite │ ├── test_parsing │ │ ├── i_number_double_huge_neg_exp.json │ │ ├── i_number_huge_exp.json │ │ ├── i_number_neg_int_huge_exp.json │ │ ├── i_number_pos_double_huge_exp.json │ │ ├── i_number_real_neg_overflow.json │ │ ├── i_number_real_pos_overflow.json │ │ ├── i_number_real_underflow.json │ │ ├── i_number_too_big_neg_int.json │ │ ├── i_number_too_big_pos_int.json │ │ ├── i_number_very_big_negative_int.json │ │ ├── i_object_key_lone_2nd_surrogate.json │ │ ├── i_string_1st_surrogate_but_2nd_missing.json │ │ ├── i_string_1st_valid_surrogate_2nd_invalid.json │ │ ├── i_string_UTF-16LE_with_BOM.json │ │ ├── i_string_UTF-8_invalid_sequence.json │ │ ├── i_string_UTF8_surrogate_U+D800.json │ │ ├── i_string_incomplete_surrogate_and_escape_valid.json │ │ ├── i_string_incomplete_surrogate_pair.json │ │ ├── i_string_incomplete_surrogates_escape_valid.json │ │ ├── i_string_invalid_lonely_surrogate.json │ │ ├── i_string_invalid_surrogate.json │ │ ├── i_string_invalid_utf-8.json │ │ ├── i_string_inverted_surrogates_U+1D11E.json │ │ ├── i_string_iso_latin_1.json │ │ ├── i_string_lone_second_surrogate.json │ │ ├── i_string_lone_utf8_continuation_byte.json │ │ ├── i_string_not_in_unicode_range.json │ │ ├── i_string_overlong_sequence_2_bytes.json │ │ ├── i_string_overlong_sequence_6_bytes.json │ │ ├── i_string_overlong_sequence_6_bytes_null.json │ │ ├── i_string_truncated-utf-8.json │ │ ├── i_string_utf16BE_no_BOM.json │ │ ├── i_string_utf16LE_no_BOM.json │ │ ├── i_structure_500_nested_arrays.json │ │ ├── i_structure_UTF-8_BOM_empty_object.json │ │ ├── n_array_1_true_without_comma.json │ │ ├── n_array_a_invalid_utf8.json │ │ ├── n_array_colon_instead_of_comma.json │ │ ├── n_array_comma_after_close.json │ │ ├── n_array_comma_and_number.json │ │ ├── n_array_double_comma.json │ │ ├── n_array_double_extra_comma.json │ │ ├── n_array_extra_close.json │ │ ├── n_array_extra_comma.json │ │ ├── n_array_incomplete.json │ │ ├── n_array_incomplete_invalid_value.json │ │ ├── n_array_inner_array_no_comma.json │ │ ├── n_array_invalid_utf8.json │ │ ├── n_array_items_separated_by_semicolon.json │ │ ├── n_array_just_comma.json │ │ ├── n_array_just_minus.json │ │ ├── n_array_missing_value.json │ │ ├── n_array_newlines_unclosed.json │ │ ├── n_array_number_and_comma.json │ │ ├── n_array_number_and_several_commas.json │ │ ├── n_array_spaces_vertical_tab_formfeed.json │ │ ├── n_array_star_inside.json │ │ ├── n_array_unclosed.json │ │ ├── n_array_unclosed_trailing_comma.json │ │ ├── n_array_unclosed_with_new_lines.json │ │ ├── n_array_unclosed_with_object_inside.json │ │ ├── n_incomplete_false.json │ │ ├── n_incomplete_null.json │ │ ├── n_incomplete_true.json │ │ ├── n_multidigit_number_then_00.json │ │ ├── n_number_++.json │ │ ├── n_number_+1.json │ │ ├── n_number_+Inf.json │ │ ├── n_number_-01.json │ │ ├── n_number_-1.0..json │ │ ├── n_number_-2..json │ │ ├── n_number_-NaN.json │ │ ├── n_number_.-1.json │ │ ├── n_number_.2e-3.json │ │ ├── n_number_0.1.2.json │ │ ├── n_number_0.3e+.json │ │ ├── n_number_0.3e.json │ │ ├── n_number_0.e1.json │ │ ├── n_number_0_capital_E+.json │ │ ├── n_number_0_capital_E.json │ │ ├── n_number_0e+.json │ │ ├── n_number_0e.json │ │ ├── n_number_1.0e+.json │ │ ├── n_number_1.0e-.json │ │ ├── n_number_1.0e.json │ │ ├── n_number_1_000.json │ │ ├── n_number_1eE2.json │ │ ├── n_number_2.e+3.json │ │ ├── n_number_2.e-3.json │ │ ├── n_number_2.e3.json │ │ ├── n_number_9.e+.json │ │ ├── n_number_Inf.json │ │ ├── n_number_NaN.json │ │ ├── n_number_U+FF11_fullwidth_digit_one.json │ │ ├── n_number_expression.json │ │ ├── n_number_hex_1_digit.json │ │ ├── n_number_hex_2_digits.json │ │ ├── n_number_infinity.json │ │ ├── n_number_invalid+-.json │ │ ├── n_number_invalid-negative-real.json │ │ ├── n_number_invalid-utf-8-in-bigger-int.json │ │ ├── n_number_invalid-utf-8-in-exponent.json │ │ ├── n_number_invalid-utf-8-in-int.json │ │ ├── n_number_minus_infinity.json │ │ ├── n_number_minus_sign_with_trailing_garbage.json │ │ ├── n_number_minus_space_1.json │ │ ├── n_number_neg_int_starting_with_zero.json │ │ ├── n_number_neg_real_without_int_part.json │ │ ├── n_number_neg_with_garbage_at_end.json │ │ ├── n_number_real_garbage_after_e.json │ │ ├── n_number_real_with_invalid_utf8_after_e.json │ │ ├── n_number_real_without_fractional_part.json │ │ ├── n_number_starting_with_dot.json │ │ ├── n_number_with_alpha.json │ │ ├── n_number_with_alpha_char.json │ │ ├── n_number_with_leading_zero.json │ │ ├── n_object_bad_value.json │ │ ├── n_object_bracket_key.json │ │ ├── n_object_comma_instead_of_colon.json │ │ ├── n_object_double_colon.json │ │ ├── n_object_emoji.json │ │ ├── n_object_garbage_at_end.json │ │ ├── n_object_key_with_single_quotes.json │ │ ├── n_object_lone_continuation_byte_in_key_and_trailing_comma.json │ │ ├── n_object_missing_colon.json │ │ ├── n_object_missing_key.json │ │ ├── n_object_missing_semicolon.json │ │ ├── n_object_missing_value.json │ │ ├── n_object_no-colon.json │ │ ├── n_object_non_string_key.json │ │ ├── n_object_non_string_key_but_huge_number_instead.json │ │ ├── n_object_repeated_null_null.json │ │ ├── n_object_several_trailing_commas.json │ │ ├── n_object_single_quote.json │ │ ├── n_object_trailing_comma.json │ │ ├── n_object_trailing_comment.json │ │ ├── n_object_trailing_comment_open.json │ │ ├── n_object_trailing_comment_slash_open.json │ │ ├── n_object_trailing_comment_slash_open_incomplete.json │ │ ├── n_object_two_commas_in_a_row.json │ │ ├── n_object_unquoted_key.json │ │ ├── n_object_unterminated-value.json │ │ ├── n_object_with_single_string.json │ │ ├── n_object_with_trailing_garbage.json │ │ ├── n_single_space.json │ │ ├── n_string_1_surrogate_then_escape.json │ │ ├── n_string_1_surrogate_then_escape_u.json │ │ ├── n_string_1_surrogate_then_escape_u1.json │ │ ├── n_string_1_surrogate_then_escape_u1x.json │ │ ├── n_string_accentuated_char_no_quotes.json │ │ ├── n_string_backslash_00.json │ │ ├── n_string_escape_x.json │ │ ├── n_string_escaped_backslash_bad.json │ │ ├── n_string_escaped_ctrl_char_tab.json │ │ ├── n_string_escaped_emoji.json │ │ ├── n_string_incomplete_escape.json │ │ ├── n_string_incomplete_escaped_character.json │ │ ├── n_string_incomplete_surrogate.json │ │ ├── n_string_incomplete_surrogate_escape_invalid.json │ │ ├── n_string_invalid-utf-8-in-escape.json │ │ ├── n_string_invalid_backslash_esc.json │ │ ├── n_string_invalid_unicode_escape.json │ │ ├── n_string_invalid_utf8_after_escape.json │ │ ├── n_string_leading_uescaped_thinspace.json │ │ ├── n_string_no_quotes_with_bad_escape.json │ │ ├── n_string_single_doublequote.json │ │ ├── n_string_single_quote.json │ │ ├── n_string_single_string_no_double_quotes.json │ │ ├── n_string_start_escape_unclosed.json │ │ ├── n_string_unescaped_crtl_char.json │ │ ├── n_string_unescaped_newline.json │ │ ├── n_string_unescaped_tab.json │ │ ├── n_string_unicode_CapitalU.json │ │ ├── n_string_with_trailing_garbage.json │ │ ├── n_structure_100000_opening_arrays.json │ │ ├── n_structure_U+2060_word_joined.json │ │ ├── n_structure_UTF8_BOM_no_data.json │ │ ├── n_structure_angle_bracket_..json │ │ ├── n_structure_angle_bracket_null.json │ │ ├── n_structure_array_trailing_garbage.json │ │ ├── n_structure_array_with_extra_array_close.json │ │ ├── n_structure_array_with_unclosed_string.json │ │ ├── n_structure_ascii-unicode-identifier.json │ │ ├── n_structure_capitalized_True.json │ │ ├── n_structure_close_unopened_array.json │ │ ├── n_structure_comma_instead_of_closing_brace.json │ │ ├── n_structure_double_array.json │ │ ├── n_structure_end_array.json │ │ ├── n_structure_incomplete_UTF8_BOM.json │ │ ├── n_structure_lone-invalid-utf-8.json │ │ ├── n_structure_lone-open-bracket.json │ │ ├── n_structure_no_data.json │ │ ├── n_structure_null-byte-outside-string.json │ │ ├── n_structure_number_with_trailing_garbage.json │ │ ├── n_structure_object_followed_by_closing_object.json │ │ ├── n_structure_object_unclosed_no_value.json │ │ ├── n_structure_object_with_comment.json │ │ ├── n_structure_object_with_trailing_garbage.json │ │ ├── n_structure_open_array_apostrophe.json │ │ ├── n_structure_open_array_comma.json │ │ ├── n_structure_open_array_object.json │ │ ├── n_structure_open_array_open_object.json │ │ ├── n_structure_open_array_open_string.json │ │ ├── n_structure_open_array_string.json │ │ ├── n_structure_open_object.json │ │ ├── n_structure_open_object_close_array.json │ │ ├── n_structure_open_object_comma.json │ │ ├── n_structure_open_object_open_array.json │ │ ├── n_structure_open_object_open_string.json │ │ ├── n_structure_open_object_string_with_apostrophes.json │ │ ├── n_structure_open_open.json │ │ ├── n_structure_single_eacute.json │ │ ├── n_structure_single_star.json │ │ ├── n_structure_trailing_#.json │ │ ├── n_structure_uescaped_LF_before_string.json │ │ ├── n_structure_unclosed_array.json │ │ ├── n_structure_unclosed_array_partial_null.json │ │ ├── n_structure_unclosed_array_unfinished_false.json │ │ ├── n_structure_unclosed_array_unfinished_true.json │ │ ├── n_structure_unclosed_object.json │ │ ├── n_structure_unicode-identifier.json │ │ ├── n_structure_whitespace_U+2060_word_joiner.json │ │ ├── n_structure_whitespace_formfeed.json │ │ ├── y_array_arraysWithSpaces.json │ │ ├── y_array_empty-string.json │ │ ├── y_array_empty.json │ │ ├── y_array_ending_with_newline.json │ │ ├── y_array_false.json │ │ ├── y_array_heterogeneous.json │ │ ├── y_array_null.json │ │ ├── y_array_with_1_and_newline.json │ │ ├── y_array_with_leading_space.json │ │ ├── y_array_with_several_null.json │ │ ├── y_array_with_trailing_space.json │ │ ├── y_number.json │ │ ├── y_number_0e+1.json │ │ ├── y_number_0e1.json │ │ ├── y_number_after_space.json │ │ ├── y_number_double_close_to_zero.json │ │ ├── y_number_int_with_exp.json │ │ ├── y_number_minus_zero.json │ │ ├── y_number_negative_int.json │ │ ├── y_number_negative_one.json │ │ ├── y_number_negative_zero.json │ │ ├── y_number_real_capital_e.json │ │ ├── y_number_real_capital_e_neg_exp.json │ │ ├── y_number_real_capital_e_pos_exp.json │ │ ├── y_number_real_exponent.json │ │ ├── y_number_real_fraction_exponent.json │ │ ├── y_number_real_neg_exp.json │ │ ├── y_number_real_pos_exponent.json │ │ ├── y_number_simple_int.json │ │ ├── y_number_simple_real.json │ │ ├── y_object.json │ │ ├── y_object_basic.json │ │ ├── y_object_duplicated_key.json │ │ ├── y_object_duplicated_key_and_value.json │ │ ├── y_object_empty.json │ │ ├── y_object_empty_key.json │ │ ├── y_object_escaped_null_in_key.json │ │ ├── y_object_extreme_numbers.json │ │ ├── y_object_long_strings.json │ │ ├── y_object_simple.json │ │ ├── y_object_string_unicode.json │ │ ├── y_object_with_newlines.json │ │ ├── y_string_1_2_3_bytes_UTF-8_sequences.json │ │ ├── y_string_accepted_surrogate_pair.json │ │ ├── y_string_accepted_surrogate_pairs.json │ │ ├── y_string_allowed_escapes.json │ │ ├── y_string_backslash_and_u_escaped_zero.json │ │ ├── y_string_backslash_doublequotes.json │ │ ├── y_string_comments.json │ │ ├── y_string_double_escape_a.json │ │ ├── y_string_double_escape_n.json │ │ ├── y_string_escaped_control_character.json │ │ ├── y_string_escaped_noncharacter.json │ │ ├── y_string_in_array.json │ │ ├── y_string_in_array_with_leading_space.json │ │ ├── y_string_last_surrogates_1_and_2.json │ │ ├── y_string_nbsp_uescaped.json │ │ ├── y_string_nonCharacterInUTF-8_U+10FFFF.json │ │ ├── y_string_nonCharacterInUTF-8_U+FFFF.json │ │ ├── y_string_null_escape.json │ │ ├── y_string_one-byte-utf-8.json │ │ ├── y_string_pi.json │ │ ├── y_string_reservedCharacterInUTF-8_U+1BFFF.json │ │ ├── y_string_simple_ascii.json │ │ ├── y_string_space.json │ │ ├── y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json │ │ ├── y_string_three-byte-utf-8.json │ │ ├── y_string_two-byte-utf-8.json │ │ ├── y_string_u+2028_line_sep.json │ │ ├── y_string_u+2029_par_sep.json │ │ ├── y_string_uEscape.json │ │ ├── y_string_uescaped_newline.json │ │ ├── y_string_unescaped_char_delete.json │ │ ├── y_string_unicode.json │ │ ├── y_string_unicodeEscapedBackslash.json │ │ ├── y_string_unicode_2.json │ │ ├── y_string_unicode_U+10FFFE_nonchar.json │ │ ├── y_string_unicode_U+1FFFE_nonchar.json │ │ ├── y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json │ │ ├── y_string_unicode_U+2064_invisible_plus.json │ │ ├── y_string_unicode_U+FDD0_nonchar.json │ │ ├── y_string_unicode_U+FFFE_nonchar.json │ │ ├── y_string_unicode_escaped_double_quote.json │ │ ├── y_string_utf8.json │ │ ├── y_string_with_del_character.json │ │ ├── y_structure_lonely_false.json │ │ ├── y_structure_lonely_int.json │ │ ├── y_structure_lonely_negative_real.json │ │ ├── y_structure_lonely_null.json │ │ ├── y_structure_lonely_string.json │ │ ├── y_structure_lonely_true.json │ │ ├── y_structure_string_empty.json │ │ ├── y_structure_trailing_newline.json │ │ ├── y_structure_true_in_array.json │ │ └── y_structure_whitespace_array.json │ └── test_transform │ │ ├── number_-9223372036854775808.json │ │ ├── number_-9223372036854775809.json │ │ ├── number_1.0.json │ │ ├── number_1.000000000000000005.json │ │ ├── number_1000000000000000.json │ │ ├── number_10000000000000000999.json │ │ ├── number_1e-999.json │ │ ├── number_1e6.json │ │ ├── number_9223372036854775807.json │ │ ├── number_9223372036854775808.json │ │ ├── object_key_nfc_nfd.json │ │ ├── object_key_nfd_nfc.json │ │ ├── object_same_key_different_values.json │ │ ├── object_same_key_same_value.json │ │ ├── object_same_key_unclear_values.json │ │ ├── string_1_escaped_invalid_codepoint.json │ │ ├── string_1_invalid_codepoint.json │ │ ├── string_2_escaped_invalid_codepoints.json │ │ ├── string_2_invalid_codepoints.json │ │ ├── string_3_escaped_invalid_codepoints.json │ │ ├── string_3_invalid_codepoints.json │ │ └── string_with_escaped_NULL.json ├── arrays.jsonp ├── ec2-describe-instances.json └── package.json └── transform ├── and.bash ├── collect.bash ├── concat.bash ├── cons.bash ├── do.bash ├── dup.bash ├── exists.bash ├── h.bash ├── idx.bash ├── if.bash ├── json-test-suite.bash ├── k.bash ├── keyval.bash ├── map.bash ├── match.bash ├── not.bash ├── or.bash ├── pop.bash ├── push.bash ├── swap.bash ├── t.bash ├── test.bash ├── uniq.bash └── v.bash /README.md: -------------------------------------------------------------------------------- 1 | jp 2 | == 3 | A JSON processor: it takes a stream of JSON text, parses it onto a stack, optionally transforms it, and then prints it out. jp automatically detects multiline JSON, and JSON per line input. 4 | 5 | jp [options] [arg ...] 6 | 7 | echo '[{"id":1},{"id":2}]' | jp .map .v 8 | 2 9 | 1 10 | 11 | To get productive with jp quickly, try out the [tutorial](#tutorial). If you are trying to use jp and struggling, try [tech-support](#tech-support). 12 | 13 | Options 14 | ------- 15 | 16 | -d launch transform debugger 17 | -h set repl history file (default is `.history`) 18 | -H do not load/save repl history 19 | -i set indent value (default is two spaces) 20 | -m load macros from a file (option can be given multiple times) 21 | -p force pretty print output (default to tty) 22 | -P force plain output (default to non-tty) 23 | -r launch REPL 24 | -s silent, disable print step 25 | 26 | 27 | Parse 28 | ----- 29 | If jp received any input, it parses the incoming JSON stream into an array of tokens that are pushed onto its stack. If it detects any malformed JSON it will emit an error and exit non-zero. 30 | 31 | jp passes 314/318 of the [JSONTestSuite](https://github.com/nst/JSONTestSuite) parsing tests, making it one of the strongest validators. The failed tests are all related to null byte detection: 32 | 33 | n_multidigit_number_then_00.json 34 | n_string_unescaped_crtl_char.json 35 | n_string_unescaped_newline.json 36 | n_structure_null-byte-outside-string.json 37 | 38 | Unlike some parsers, jp preserves object key order, and permits duplicate keys in objects. 39 | 40 | 41 | Transform 42 | --------- 43 | If jp received any input and it was successfully parsed into tokens, they will be in a single item on Top Of Stack ("TOS"). The transform stage is an opportunity to manipulate the stack with programming via args. jp processes its args at least once; when it receives JSON-per-line input it will process its args for each line. E.g: this program receives a stream of incrementing numbers and builds a JSON array containing the number and whether or not it is greater than 2: 44 | 45 | echo -e '1\n2\n3' | jp -P .dup 2 .gt [] .swap .cons .swap .cons 46 | [1,false] 47 | [2,false] 48 | [3,true] 49 | 50 | 51 | ### Stack Control 52 | 53 | #### JSON values 54 | Any JSON literal will be parsed and pushed onto the stack, here's a string: 55 | 56 | jp '"howdy"' 57 | "howdy" 58 | 59 | #### .pop 60 | Pops the the stack, deleting TOS. 61 | 62 | jp 1 .pop 63 | # no output as stack is empty 64 | 65 | #### .swap 66 | Swaps the top two stack items with each other. 67 | 68 | jp '"Hello"' '"World!"' .swap 69 | "Hello" 70 | "World!" 71 | 72 | #### .dup 73 | Copies TOS making it the top two items. 74 | 75 | jp '"Hello"' .dup 76 | "Hello" 77 | "Hello" 78 | 79 | #### .over 80 | Copies and pushes the second stack item ("over" the first). 81 | 82 | jp 1 2 .over 83 | 1 84 | 2 85 | 1 86 | 87 | #### .rot 88 | Rotates the third stack item into first place. 89 | 90 | jp 1 2 3 .rot 91 | 1 92 | 3 93 | 2 94 | 95 | ### Reflection 96 | 97 | #### .count 98 | Pushes a count of items on the stack. 99 | 100 | jp 1 1 1 .count 101 | 3 102 | 1 103 | 1 104 | 1 105 | 106 | #### .empty 107 | This macro pushes true if the stack is empty, or false otherwise. 108 | 109 | jp -m macros.jp .empty 110 | true 111 | 112 | #### .is_obj, .is_arr, .is_bool, .is_str, .is_num, .is_null 113 | Inspects TOS and pushes true or false. 114 | 115 | jp -P [1,2,3] .is_arr 116 | true 117 | [1,2,3] 118 | 119 | ### Control Flow 120 | 121 | #### .do .. .done 122 | Declares a block of code as a single statement, must be terminated with `.done`. Do blocks can be nested. 123 | 124 | jp .do 1 2 3 .done 125 | 3 126 | 2 127 | 1 128 | 129 | Empty do blocks can be used as a "no op" with `.map` to unroll an object or array: 130 | 131 | jp [1,2,3] .map .do .done 132 | 3 133 | 2 134 | 1 135 | 136 | jp -P '{"name":"Lex Luthor","email":"lex@example.com","job":"villain"}' .map .do .done 137 | {"job":"villain"} 138 | {"email":"lex@example.com"} 139 | {"name":"Lex Luthor"} 140 | 141 | #### .if [.else] 142 | Pops TOS and if it is true, evaluates the next statement, otherwise ignoring it. Optionally accepts an else clause. 143 | 144 | jp true .if 1 145 | 1 146 | 147 | jp false .if .do 1 2 3 .done .else 4 148 | 4 149 | 150 | #### .map 151 | Pops an object/array off the stack and pushes each element onto the stack one by one, evaluating the next statement every iteration. 152 | 153 | jp [1,2,3] .map .do 3 .le .done 154 | true 155 | false 156 | false 157 | 158 | Map is powerful. For example here's how to delete a pair from an object: 159 | 160 | jp '{"a":1,"b":2,"c":3}' {} .swap .map .do .dup .k '"a"' .eq .if .pop .else .concat .done 161 | { 162 | "c": 3, 163 | "b": 2 164 | } 165 | 166 | ### Logic 167 | All of the logic functions are implemented as macros in the file `macros.jp`. 168 | 169 | #### .and 170 | Returns the conjunction of the top two stack items. 171 | 172 | jp -m macros.jp true false .and 173 | false 174 | 175 | #### .or 176 | Returns the disjunction of the top two stack items. 177 | 178 | jp -m macros.jp true false .or 179 | true 180 | 181 | #### .not 182 | Returns the logical complement (negation) of TOS. 183 | 184 | jp -m macros.jp true .not 185 | false 186 | 187 | #### .exists 188 | Pops a string off the stack, then pops an object. Pushes true/false depending on whether the string is found as a key in the object. 189 | 190 | jp -m macros.jp '{"a":1}' '"b"' .exists 191 | false 192 | 193 | ### Comparisons 194 | 195 | #### .lt .le .eq .ne .ge .gt 196 | Pops the top two stack items and pushes true/false depending on the result of the comparison. Bash can only compare integers and strings. 197 | 198 | jp 1 2 .eq 199 | false 200 | 201 | N.B. Bash's test function does not support "greater-than-or-equal" or "less-than-or-equal" string comparisons. 202 | 203 | #### .ltarr .eqarr .gtarr 204 | Filters an array by a comparison to a number or string (macro). 205 | 206 | jp -m macros.jp -P [1,2,3,4,5] 3 .ltarr 207 | [1,2] 208 | 209 | #### .match 210 | Pops TOS which should be a string containing an extended posix pattern. Pops the next item (which should be a string or number) compares them, pushing true/false onto the stack. 211 | 212 | jp 5 '"^[0-9]+$"' .match 213 | true 214 | 215 | ### Changing Data 216 | 217 | #### .concat 218 | Concatenate the top two strings, arrays or objects on the stack into one value. 219 | 220 | jp '" World!"' '"Hello,"' .concat 221 | "Hello, World!" 222 | 223 | jp '["JavaScript","PHP","Perl"]' '["Python"]' .concat 224 | [ 225 | "Python", 226 | "JavaScript", 227 | "PHP", 228 | "Perl" 229 | ] 230 | 231 | jp '{"name":"Lex Luthor", "email":"lex@example.com"}' '{"job":"villain"}' .concat 232 | { 233 | "job": "villain", 234 | "name": "Lex Luthor", 235 | "email": "lex@example.com" 236 | } 237 | 238 | `.concat` can be combined with `.map` to create filter, delete and update routines. 239 | 240 | #### .cons 241 | Pops a value off the stack, then pops an array and prepends the value to the array, pushing the new array back onto the stack. 242 | 243 | jp -P [2,3] 1 .cons 244 | [1,2,3] 245 | 246 | Can be used with `.map` to reverse an array: 247 | 248 | jp -P [1,2,3] [] .swap .map .cons 249 | [3,2,1] 250 | 251 | Indeed this is the definition of the `.revarr` macro. 252 | 253 | #### .fromstr 254 | Pops a string off the stack, strips its outer quotes and re-parses it as JSON. This can be used to cast a valid JSON string into any other JSON type. As `.ex` command output is always treated as strings, the two commands often go together: 255 | 256 | jp '"date"' '"+%s"' 2 .ex .fromstr 257 | 1639074686 258 | 259 | #### .h 260 | Pops an array off the stack, pushing the first element (head). To get the remainder of the array, see `.t` 261 | 262 | jp [1,2,3] .h 263 | 1 264 | 265 | #### .ht 266 | This macro splits a TOS array into its head and tail: 267 | 268 | jp -P -m macros.jp [1,2,3] .ht 269 | 1 270 | [2,3] 271 | 272 | #### .idx 273 | Pops an integer and an array off the stack, pushing the element from the array which matches the index number. Index number must be 0 or higher. Pushes nothing if the index number is greater than the array length. 274 | 275 | jp '["foo","bar","baz"]' 1 .idx 276 | "bar" 277 | 278 | #### .k 279 | Pops an object off the stack, pushing the first key back on the stack. See also `.v`. 280 | 281 | jp '{"a":1,"b":2}' .k 282 | "a" 283 | 284 | #### .keyval 285 | Pops a string and an object off the stack, pushing the value of the first pair with a matching key in the object. 286 | 287 | jp '{"a":1,"b":2}' '"b"' .keyval 288 | 2 289 | 290 | #### .len 291 | Pops an array and pushes its length: 292 | 293 | jp [1,2,3] .len 294 | 3 295 | 296 | #### .pair 297 | Pops TOS, which must be a string. Pops the next item as its value and pushes an object with a single pair back onto the stack. 298 | 299 | jp 123 '"a"' .pair 300 | { 301 | "a": 123 302 | } 303 | 304 | #### .sort 305 | This macro sorts an array in ascending order using quicksort. The array elements must all be strings or integers. 306 | 307 | jp -m macros.jp -P '["h","a","e","p","r"]' .sort 308 | ["a","e","h","p","r"] 309 | 310 | #### .t 311 | Pops an array off the stack, removes the first element (head) and pushes the remainder (tail). To get the head of the array, see `.h` 312 | 313 | jp [1,2,3] .t 314 | [ 315 | 2, 316 | 3 317 | ] 318 | 319 | #### .uniq 320 | Pops an object off the stack, pushing the object back with any duplicate keys removed. The first key wins: 321 | 322 | jp '{"a":1,"a":2}' .uniq 323 | { 324 | "a": 1 325 | } 326 | 327 | Want the last key to win? Reverse the object first: 328 | 329 | jp '{"a":1,"a":2}' {} .swap .map .do .concat .done .uniq 330 | { 331 | "a": 2 332 | } 333 | 334 | #### .v 335 | Pops an object off the stack, pushing the first value back on the stack. See also `.k`. 336 | 337 | jp '{"a":1,"b":2}' .v 338 | 1 339 | 340 | ### Programming 341 | 342 | #### .def 343 | Define a macro. Reads the next arg as the macro name (must begin with .). The following statement is used as the macro body. Whenever the name is encountered, it will be replaced with the macro body. Once defined, macros cannot be changed and redefinitions are ignored. 344 | 345 | jp .def .abc .do '"a"' '"b"' '"c"' .done .abc 346 | "c" 347 | "b" 348 | "a" 349 | 350 | Because macros are lazily evaluated, they can recurse. This macro cons every stack item into an array on TOS: 351 | 352 | jp .def .consall .do .count 1 .gt .if .do .swap .cons .consall .done .done 1 2 3 [] .consall 353 | [ 354 | 1, 355 | 2, 356 | 3 357 | ] 358 | 359 | You can load a file of macro definitions by providing the `-m` option. Macro files are loaded line-by-line, so macro definitions cannot contain newlines. This repo has an example macros file, `macros.jp`: 360 | 361 | # load the .exists macro 362 | jp -m macros.jp '{"a":1}' '"a"' .exists 363 | true 364 | 365 | You can load multiple macro files by repeating the `-m` option. 366 | 367 | Two advantages of defining macros in a file: first, they are only parsed once per jp process and second, arguments do not need to be quoted like they do on the command line: 368 | 369 | .def .abc .do "a" "b" "c" .done 370 | 371 | #### .dump 372 | Prints the contents of the stack to stderr, starting with `TOS` and ending with `---`: 373 | 374 | jp [1,2,3] false null '"foo"' .dump 1>/dev/null 375 | TOS "foo" 376 | 2 null 377 | 3 false 378 | 4 [1,2,3] 379 | --- 380 | 381 | Dump will indicate when the stack is empty: 382 | 383 | jp .dump 384 | TOS (empty) 385 | --- 386 | 387 | Dump can serve as a simple debugging aid for programs, like print statements for other languages. Debug mode (option `-d`) will call `.dump` every step of a program. 388 | 389 | #### .ex 390 | Executes another program, stringifies its output and pushes it onto the stack. Pops the number of args to collect off the stack, and then pops that many args, building a command string by stripping surrounding quotes and prepending the result to the command string. Evals the command string and stringifies the output, pushing it back onto the stack. 391 | 392 | jp '"date"' 1 .ex 393 | "Thu 09 Dec 2021 01:54:08 PM EST" 394 | 395 | Note the command args are prepended into the command string so they are backwards on the stack, but this makes them easier to read. Even if the quoting does get gnarly (see `.q`): 396 | 397 | jp '"perl"' '"-E"' $'"\'say for 1..5\'"' 3 .ex 398 | "5" 399 | "4" 400 | "3" 401 | "2" 402 | "1" 403 | 404 | If the output is valid JSON, `.fromstr` can be used to cast the string into another value: 405 | 406 | jp '"date"' '"+%s"' 2 .ex .fromstr 407 | 1639076249 408 | 409 | #### .q and .nq 410 | Quoting command line args can get pretty tiresome, so `.q` enables quote mode, which causes jp to wrap any JSON arg in quotes. The `.nq` command disables quote mode. Args must still be quoted to avoid word splitting. The `.ex` example condenses nicely: 411 | 412 | jp .q perl -E "'say for 1..5'" .nq 3 .ex 413 | "5" 414 | "4" 415 | "3" 416 | "2" 417 | "1" 418 | 419 | Print 420 | ----- 421 | jp prints whatever data is left on the stack after the transform stage. By default jp pretty prints JSON when printing to the terminal. You can override this behavior with the -p and -P options: 422 | 423 | # pretty but piped 424 | jp -p [1,2,3] | head 425 | [ 426 | 1, 427 | 2, 428 | 3 429 | ] 430 | 431 | # terse but in the terminal 432 | jp -P [1,2,3] 433 | [1,2,3] 434 | 435 | The default indent for pretty printing is two spaces but you can override it with the -i option: 436 | 437 | # tab indent 438 | jp -i ' ' '{"foo":[1,2,3]}' 439 | { 440 | "foo": [ 441 | 1, 442 | 2, 443 | 3 444 | ] 445 | } 446 | 447 | If you just want to use jp as a JSON validator and don't need the output, use silent mode `-s` and check the return code is zero: 448 | 449 | jp -s [1,2,3] && echo "valid!" 450 | valid! 451 | 452 | N.B. errors are emitted on stderr, to silence them, redirect: 453 | 454 | jp -s [1,2,] 2>/dev/null 455 | # no error output 456 | 457 | REPL 458 | ---- 459 | Run jp with the `-r` option to launch the REPL: 460 | 461 | ``` 462 | Welcome to the jp REPL. Type commands and ENTER to evaluate, q quits. 463 | > 464 | TOS (empty) 465 | --- 466 | ``` 467 | 468 | This interactive mode reads commands, evaluates them, updates the stack and prints the stack contents. Multiple commands can be entered on one line. This a good way to try out commands and see their effect on the stack. 469 | 470 | REPL history is stored in `.history`. As with the bash command line, Ctrl-R searches the history and the up key displays the next most recent command. Commands that generated an error are not saved in the history. The history file can be changed with the `-h` option, or disabled entirely with `-H`. 471 | 472 | 473 | Use jp as a library 474 | ------------------- 475 | jp is a [modulino](https://blog.dnmfarrell.com/post/modulinos-in-bash/). All of its functions and global variables are namespaced under `jp_` or `JP_`. If jp is sourced, it will not execute the main function, and it can be used as a library by other scripts. 476 | 477 | Install 478 | ------- 479 | Clone this repo: 480 | 481 | git clone git@github.com:dnmfarrell/jp 482 | 483 | Add the root project dir to your PATH, or copy the file to a directory in your PATH. 484 | 485 | 486 | Run test suite 487 | -------------- 488 | Tests are shell scripts which emit [TAP](https://testanything.org/) output. You can run them with [prove](https://perldoc.perl.org/prove) (comes with Perl). I wrote a blog [post](https://blog.dnmfarrell.com/post/unit-testing-shell-scripts/) about this setup. 489 | 490 | From the root project directory: 491 | 492 | prove tests/**/*.bash 493 | ... 494 | All tests successful. 495 | Files=28, Tests=473, 6 wallclock secs ( 0.16 usr 0.04 sys + 5.34 cusr 1.11 csys = 6.65 CPU) 496 | Result: PASS 497 | 498 | Shell Native 499 | ------------ 500 | jp is a shell native program, that is, it is written in the same programming language used to program the shell. This has some benefits: 501 | 502 | 1. Users of the program do not need to learn another DSL for transforming JSON. Args are just function names and JSON data. 503 | 2. Being written in shell code in a single file, all users need to modify jp is a text editor. All they need to run it is Bash 4.3 or higher. 504 | 3. Learning to program jp means learning shell, which is a useful skill that users can employ to build their own programs, understand the command line better, and so on. 505 | 4. jp can be used as a program, and as a library to provide behavior to other shell scripts. 506 | 507 | Being shell native has some downsides too: 508 | 1. Shell code's limited support for programming concepts like data structures, return values and so on make it difficult to create apps in. 509 | 2. jp is not as fast as [jq](https://stedolan.github.io/jq/)! 510 | 3. Users have to be familiar with shell programming to get the most out of the program 511 | 512 | All that's needed to solve these issues is a better shell programming language which is really fast, portable and used everywhere. 513 | 514 | 515 | Improvements 516 | ------------ 517 | * jp is a recursive descent parser; this means it doesn't need to store a lot of state, it just traverses the data structure. The downside is it will gladly recurse down any data structure until the stack becomes full and it crashes. On my computer this happens after recursing through ~2000 nested arrays. A different parsing strategy would be more robust. 518 | 519 | 520 | Other Shell JSON Parsers 521 | ------------------------ 522 | These parse a JSON stream of text, and output a linear tree of paths which can be grepped: 523 | * [JSON.sh](https://github.com/dominictarr/JSON.sh/) is compatible with ash, bash, dash and zsh 524 | * [JSON.bash](https://github.com/ingydotnet/git-hub/tree/master/ext/json-bash) is a source-able bash library 525 | 526 | [TickTick](https://github.com/kristopolous/TickTick) is a Bash library which provides inline JSON parsing and searching. 527 | 528 | Tech Support 529 | ------------ 530 | If you are trying to use jp and running into difficulty, I want to hear from you! Please open a new [issue](https://github.com/dnmfarrell/jp/issues/new?labels=tech-support&title=%3CI%27m%20having%20difficulty%20with%20...%3E&body=%3CI%27ve%20tried%20...%3E%0A%0A%3Cattach%20sample%20JSON%20if%20any%3E). Include any JSON input data you are using, a brief description of what you are trying to accomplish, and what you've tried so far. I can't provide any service guarantees, but when I have time I'll look at your issue and try to provide a solution. 531 | 532 | Tutorial 533 | -------- 534 | ### Intro 535 | This tutorial will show you how to accomplish simple transformations on JSON objects like add, update, and delete. You'll need to [install](#install) jp and start a bash shell session. I recommend typing out all of the code examples yourself to better understand (and remember) what's going on. If you have suggestions for how this tutorial could be better please let me know by opening a new [issue](https://github.com/dnmfarrell/jp/issues/new?labels=tutorial). 536 | 537 | To demonstrate I need some input data, so I'm going to use a shortened version of my GitHub profile. If you have a GitHub account, you can download your own JSON profile with curl (replace `gh_username` with your github username): 538 | 539 | curl https://api.github.com/users/gh_username > gh-profile.json 540 | 541 | The first thing to get comfortable with is passing data into jp, which we can do using `cat` and pipe: 542 | 543 | cat gh-profile.json | jp 544 | { 545 | "login": "dnmfarrell", 546 | "id": 1469333, 547 | "url": "https://api.github.com/users/dnmfarrell", 548 | "type": "User", 549 | "site_admin": false, 550 | "name": "David Farrell", 551 | "blog": "blog.dnmfarrell.com", 552 | "location": "Buccaneer's Den, Britannia", 553 | "twitter_username": "perltricks", 554 | "public_repos": 147, 555 | "created_at": "2012-02-24T11:56:06Z" 556 | } 557 | 558 | N.B. Because jp's parent directory is in my PATH environment variable, I don't need to provide the shell with the full path to `jp`. If jp is not in your PATH, you'll need to provide the path to jp. For example, if you cloned this repo and are currently in the root project dir, `./jp` is the relative path to the program. 559 | 560 | All jp does is print the content back onto the terminal. What is the use in that? For one thing the fact that jp did not report an error means I know this JSON is syntactically correct. If that's all I care about though, I can give jp the silent option `-s`: 561 | 562 | cat gh-profile.json | jp -s 563 | 564 | Now imagine I want to collapse the JSON into a single line of text, to make it easy to use as input for an API request. The plain print `-P` does that: 565 | 566 | cat gh-profile.json | jp -P 567 | {"login":"dnmfarrell", ...} 568 | 569 | (I've truncated the output for brevity, from now on whenever you see the ellipsis `...` just imagine it represents the rest of the data). 570 | 571 | That just about covers parsing input and printing output. The real action happens between parsing and printing. That's called the transform stage. 572 | 573 | ### Extract 574 | Let's extract my twitter username: 575 | 576 | cat gh-profile.json | jp '"twitter_username"' .keyval 577 | "perltricks" 578 | 579 | Note that the string `"perltricks"` is valid JSON. jp always prints JSON (or error messages). 580 | 581 | ### Delete 582 | I can delete pairs from objects using the `.deleteobj` macro; e.g. to delete the twitter username pair: 583 | 584 | cat gh-profile.json | jp -m macros.jp '"twitter_username"' .deleteobj 585 | { 586 | "login": "dnmfarrell", 587 | "id": 1469333, 588 | "url": "https://api.github.com/users/dnmfarrell", 589 | "type": "User", 590 | "site_admin": false, 591 | "name": "David Farrell", 592 | "blog": "blog.dnmfarrell.com", 593 | "location": "Buccaneer's Den, Britannia", 594 | "public_repos": 147, 595 | "created_at": "2012-02-24T11:56:06Z" 596 | } 597 | 598 | I've used a new option `-m` to load the macros helper file as that's where `.deleteobj` is defined. 599 | 600 | ### Add 601 | Here's how to add data to an object: 602 | 603 | cat gh-profile.json | jp '{"favorite_food":"pizza"}' .concat 604 | { 605 | "favorite_food": "pizza", 606 | "login": "dnmfarrell", 607 | ... 608 | } 609 | 610 | I pass the JSON object I want to add and use `.concat` to combine them. My "favorite\_food" pair has been prepended to the object. What if I want to _append_ it instead? In that case I need to swap the stack order so `.concat` gets the "favorite\_food" object as its second arg: 611 | 612 | cat gh-profile.json | jp '{"favorite_food":"pizza"}' .swap .concat 613 | { 614 | "login": "dnmfarrell", 615 | ... 616 | "favorite_food": "pizza" 617 | } 618 | 619 | ### Update / Upsert 620 | Perhaps I want to hide my location before sending the data elsewhere: 621 | 622 | cat gh-profile.json | jp -m macros.jp '{"location":null}' .updateobj 623 | { 624 | "login": "dnmfarrell", 625 | ... 626 | "location": null, 627 | ... 628 | } 629 | 630 | I've used the `.updateobj` macro to nullify the location value. The difference between update and add is that update will only take effect if the key "location" exists, whereas add will always add data to the object. 631 | 632 | An upsert operation is yet another way to modify data: if the key exists, update it, otherwise insert the data. The `.upsertobj` macro does this. 633 | 634 | ### Programming 635 | So far all of these conditional operations are key based. That means the input string needs to exactly match the pair key to take effect. What if I want to take some action based on a pair _value_ instead? Now I can't use a predefined macro, I have to program the transformation myself. 636 | 637 | For this scenario, imagine I am streaming GitHub user profiles to jp, and want to filter my profile out of the stream. 638 | 639 | First I need to extract the login pair: 640 | 641 | cat gh-profile.json | jp .dup '"login"' .keyval 642 | "dnmfarrell" 643 | { 644 | "login": "dnmfarrell", 645 | ... 646 | } 647 | 648 | To avoid losing the input object, I duplicate it first, with `.dup`. Then I use the `.keyval` to extract the login pair value. jp then prints the stack containing the string and the object. I find it easier to inspect the stack using plain output: 649 | 650 | cat gh-profile.json | jp -P .dup '"login"' .keyval 651 | "dnmfarrell" 652 | {"login":"dnmfarrell", ...} 653 | 654 | Now each line is one stack entry, I can easily count that there are 2 entries on the stack. Next I need to test whether the username is my own: 655 | 656 | cat gh-profile.json | jp -P .dup '"login"' .keyval '"dnmfarrell"' .eq 657 | true 658 | {"login":"dnmfarrell", ...} 659 | 660 | Now the top stack value is a boolean, I can use `.if` to take some optional action: 661 | 662 | cat gh-profile.json | jp -P .dup '"login"' .keyval '"dnmfarrell"' .eq .if .pop 663 | 664 | Because `.if` consumes the boolean, only the object is left on the stack. If it matches my username, I pop it off the stack. As the stack is empty, jp does not print anything. 665 | 666 | To simulate the stream, I downloaded the GitHub profile of Beren Minor, who (among other things) mirrors GNU repos like bash to GitHub: 667 | 668 | curl https://api.github.com/users/bminor > gh-profile-bminor.json 669 | 670 | Bash expands the argument `gh-profile*` into `gh-profile-bminor.json gh-profile.json`: 671 | 672 | cat gh-profile* | jp -P .dup '"login"' .keyval '"dnmfarrell"' .eq .if .pop 673 | {"login":"bminor", ...} 674 | 675 | jp correctly filters my profile but still emits Beren's. 676 | 677 | License 678 | ------- 679 | Copyright 2021 David Farrell 680 | 681 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 682 | 683 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 684 | 685 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 686 | -------------------------------------------------------------------------------- /jp: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2021 David Farrell 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | # 5 | # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | # 7 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | JP_NL=' 9 | ' 10 | JP_CR=' ' 11 | JP_TAB=' ' 12 | IFS="$JP_TAB" # tokens are tab delimited 13 | JP_SEP=$'\t\n' 14 | JP_STACKSIZE=0 15 | JP_HISTORY=".history" 16 | 17 | jp_error () { 18 | JP_ERROR=${1/"'$JP_NL'"/"''"} 19 | echo "Error: $JP_ERROR at line $JP_LINE, column $JP_IDX" >&2 20 | return 1 21 | } 22 | 23 | jp_debug () { 24 | if [ "${1:0:3}" = "jp_" ]&&[ "$1" != "${FUNCNAME[1]}" ];then 25 | [ $JP_DEBUG_SKIP ] && [ "$1" != "jp_next_arg" ]&&return 26 | JP_DEBUG_SKIP= 27 | echo "$1" >&2 28 | jp_dump 29 | while read -s -n 1 key;do 30 | case "$key" in 31 | "s") break;; 32 | "n") JP_DEBUG_SKIP=1;break;; 33 | "q") trap '' DEBUG;break;; 34 | *) echo "$key has no effect, try one of: s, n, q" 35 | esac 36 | done < /dev/tty 37 | fi 38 | } 39 | 40 | jp_dump () { 41 | local stack="$JP_STACK" i=1 out= label='TOS' 42 | while :;do 43 | out="${stack%%$JP_SEP*}" 44 | [ "$out" ] || out='(empty)' 45 | stack="${stack#*$JP_SEP}" 46 | echo -en "$label\t" >&2 47 | for t in $out;do 48 | echo -nE "$t" >&2 49 | done 50 | echo >&2 51 | (( i++ )) 52 | (( i > JP_STACKSIZE )) && break 53 | printf -v label "%3d" "$i" >&2 54 | done 55 | echo '---' >&2 56 | } 57 | 58 | # BEGIN PARSE FUNCTIONS 59 | jp_readline () { 60 | JP_IDX=0 JP_BUF_MAXLEN=0 JP_LINE=1 61 | if [ $JP_INPUT ];then 62 | IFS=$'\n' read -r JP_BUF 63 | JP_BUF_MAXLEN="${#JP_BUF}" 64 | fi 65 | return 0 66 | } 67 | 68 | jp_chomp () { 69 | if [ $JP_BUF_MAXLEN -eq 0 ];then 70 | JP_C='' 71 | elif [ $JP_IDX -lt $JP_BUF_MAXLEN ];then 72 | JP_C="${JP_BUF:$JP_IDX:1}" 73 | JP_IDX=$(( JP_IDX + 1 )) 74 | elif [ $JP_IDX -eq $JP_BUF_MAXLEN ];then 75 | JP_C=$'\n' 76 | JP_IDX=$(( JP_IDX + 1 )) 77 | else 78 | JP_IDX=0 79 | JP_LINE=$(( JP_LINE + 1 )) 80 | jp_readline 81 | jp_chomp 82 | fi 83 | } 84 | 85 | jp_drop_ws () { 86 | while :;do 87 | case "$JP_C" in 88 | " ") jp_chomp;; 89 | "$JP_NL") jp_chomp;; 90 | "$JP_CR") jp_chomp;; 91 | "$JP_TAB") jp_chomp;; 92 | *) break;; 93 | esac 94 | done 95 | } 96 | 97 | jp_expect () { 98 | if [ "$JP_C" != "$1" ];then 99 | local msg 100 | printf -v msg "expected %q but saw %q" "$1" "$JP_C" 101 | jp_error "$msg" || return 102 | fi 103 | } 104 | 105 | jp_array () { 106 | JP_TOKENS+="[ " 107 | jp_chomp 108 | jp_drop_ws 109 | if [ "$JP_C" != ']' ];then 110 | jp_read_next || return 111 | while :;do 112 | [ "$JP_C" != '' ] || jp_error "unterminated array: didn't find ]" || return 113 | jp_drop_ws 114 | if [ "$JP_C" = ']' ];then 115 | break 116 | elif [ "$JP_C" = ',' ];then 117 | JP_TOKENS+=", " 118 | jp_chomp 119 | jp_drop_ws 120 | jp_read_next || return 121 | else 122 | jp_error "expected , or ] but saw '$JP_C'" || return 123 | fi 124 | done 125 | fi 126 | JP_TOKENS+="] " 127 | jp_chomp 128 | } 129 | 130 | jp_object () { 131 | JP_TOKENS+="{ " 132 | jp_chomp 133 | jp_drop_ws 134 | if [ "$JP_C" != '}' ];then 135 | jp_expect '"' || return 136 | jp_string 137 | jp_drop_ws 138 | jp_expect ":" || return 139 | JP_TOKENS+=": " 140 | jp_chomp 141 | jp_drop_ws 142 | jp_read_next || return 143 | while :;do 144 | [ "$JP_C" != '' ] || jp_error "unterminated object: didn't find }" return 145 | jp_drop_ws 146 | if [ "$JP_C" = '}' ];then 147 | break 148 | elif [ "$JP_C" = ',' ];then 149 | JP_TOKENS+=", " 150 | jp_chomp 151 | jp_drop_ws 152 | jp_expect '"' || return 153 | jp_string 154 | jp_drop_ws 155 | jp_expect ":" || return 156 | JP_TOKENS+=": " 157 | jp_chomp 158 | jp_drop_ws 159 | jp_read_next || return 160 | else 161 | jp_error "expected , or } but saw $JP_C" || return 162 | fi 163 | done 164 | fi 165 | JP_TOKENS+="} " 166 | jp_chomp 167 | } 168 | 169 | jp_number () { 170 | local num="$JP_C" seendot= seenexp= 171 | jp_chomp 172 | if [ "$num" = '-' ];then # negative number 173 | [[ "$JP_C" == [[:digit:]] ]] || jp_error "minus not followed by digit: $num$JP_C" || return 174 | if [ "$JP_C" = '0' ];then 175 | num="$num$JP_C" 176 | jp_chomp 177 | [[ "$JP_C" != [[:digit:]] ]] || jp_error "number starts with zero: $num$JP_C" || return 178 | fi 179 | elif [ "$num" = '0' ];then 180 | [[ $JP_C != [[:digit:]] ]] || jp_error "number starts with zero: $num$JP_C" || return 181 | fi 182 | while :;do 183 | if [[ "$JP_C" == [[:digit:]] ]];then 184 | num="$num$JP_C" 185 | elif [ "$JP_C" = . ];then 186 | if [ "$seendot" ];then 187 | jp_error "number has too many dots in it: $num$JP_C" || return 188 | elif [ "$seenexp" ];then 189 | jp_error "exponents cannot contain dots: $num$JP_C" || return 190 | else 191 | num="$num$JP_C" 192 | seendot=1 193 | jp_chomp 194 | [[ "$JP_C" == [[:digit:]] ]] || jp_error "dot not followed by digit: $num$JP_C" || return 195 | continue 196 | fi 197 | elif [[ $JP_C == [Ee] ]];then 198 | if [ $seenexp ];then 199 | jp_error "number has too many Es in it: $num$JP_C" || return 200 | fi 201 | seenexp=1 202 | num="$num$JP_C" 203 | jp_chomp 204 | if [[ $JP_C == [+-] ]];then 205 | num="$num$JP_C" 206 | jp_chomp 207 | fi 208 | if [[ $JP_C != [[:digit:]] ]];then 209 | jp_error "a number must follow an exponent or sign: $num$JP_C" || return 210 | fi 211 | num="$num$JP_C" 212 | else 213 | JP_TOKENS+="$num " 214 | break 215 | fi 216 | jp_chomp 217 | done 218 | lastchar=${num:$(( ${#num}-1 )):1} 219 | [[ "$lastchar" != [Ee.+-] ]] || jp_error "invalid number $num ($lastchar)" || return 220 | } 221 | 222 | jp_string () { 223 | local str= start_line="$JP_LINE" 224 | while :;do 225 | [ "$JP_C" != '' ] || jp_error "unterminated string: didn't find \"" || return 226 | jp_chomp 227 | if [ "$JP_LINE" -gt "$start_line" ];then 228 | jp_error "unescaped newline in string" || return 229 | elif [ "$JP_C" = $'\t' ];then 230 | jp_error "unescaped tab in string" || return 231 | elif [ "$JP_C" = $'\\' ];then # handle escapes 232 | str="$str$JP_C" 233 | jp_chomp 234 | if [ "$JP_C" = u ];then # unicode 235 | local esc="u" 236 | for i in 1 2 3 4;do 237 | jp_chomp 238 | [[ "$JP_C" == [0-9A-Fa-f] ]] || jp_error "invalid Unicode escape sequence \\$esc$JP_C" || return 239 | esc+="$JP_C" 240 | done 241 | JP_C="$esc" 242 | elif [[ "$JP_C" != [bfnrt\"$'\\'/] ]];then 243 | jp_error "invalid escape sequence in string: \\$JP_C" || return 244 | fi 245 | elif [ "$JP_C" = '"' ];then 246 | JP_TOKENS+="\"$str\" " 247 | break 248 | fi 249 | str+="$JP_C" 250 | done 251 | jp_chomp 252 | } 253 | 254 | jp_null () { 255 | jp_chomp 256 | if [ "$JP_C" = "u" ];then 257 | jp_chomp 258 | if [ "$JP_C" = "l" ];then 259 | jp_chomp 260 | if [ "$JP_C" = "l" ];then 261 | JP_TOKENS+="null " 262 | jp_chomp 263 | return 264 | fi 265 | fi 266 | fi 267 | jp_error "expected 'null' but saw '$JP_C'" || return 268 | } 269 | 270 | jp_bool_true () { 271 | jp_chomp 272 | if [ "$JP_C" = "r" ];then 273 | jp_chomp 274 | if [ "$JP_C" = "u" ];then 275 | jp_chomp 276 | if [ "$JP_C" = "e" ];then 277 | JP_TOKENS+="true " 278 | jp_chomp 279 | return 280 | fi 281 | fi 282 | fi 283 | jp_error "expected 'true' but saw '$JP_C'" || return 284 | } 285 | 286 | jp_bool_false () { 287 | jp_chomp 288 | if [ "$JP_C" = "a" ];then 289 | jp_chomp 290 | if [ "$JP_C" = "l" ];then 291 | jp_chomp 292 | if [ "$JP_C" = "s" ];then 293 | jp_chomp 294 | if [ "$JP_C" = "e" ];then 295 | JP_TOKENS+="false " 296 | jp_chomp 297 | return 298 | fi 299 | fi 300 | fi 301 | fi 302 | jp_error "expected 'false' but saw '$JP_C'" || return 303 | } 304 | 305 | jp_read_next () { 306 | case "$JP_C" in 307 | [[:digit:]-]) jp_number;; 308 | '"') jp_string;; 309 | 'n') jp_null;; 310 | 't') jp_bool_true;; 311 | 'f') jp_bool_false;; 312 | '[') jp_array;; 313 | '{') jp_object;; 314 | *) jp_error "expected 0-9, \", 't', 'f', '[', or '{' but got: '$JP_C'" 315 | esac 316 | } 317 | 318 | jp_parse_json () { 319 | JP_TOKENS= 320 | jp_chomp 321 | jp_drop_ws 322 | jp_read_next || return 323 | while [[ "$JP_C" == [[:blank:]] ]];do 324 | jp_chomp 325 | done 326 | [ "$JP_C" = $'\n' ] || jp_error "expected '\n' but saw $JP_C" || return 327 | } 328 | 329 | jp_detect_nullbyte () { 330 | local buf= 331 | IFS= read -rd '' buf 332 | [ -z "$buf" ] || jp_error "received input after null byte" || return 333 | } 334 | # END PARSE FUNCTIONS 335 | 336 | # BEGIN TRANSFORM FUNCTIONS 337 | jp_push () { 338 | JP_STACK="$1"$'\n'"$JP_STACK" # \n delimited 339 | JP_STACKSIZE=$(( JP_STACKSIZE + 1 )) 340 | return 0 341 | } 342 | 343 | jp_pop () { 344 | if [ $JP_STACKSIZE -eq 0 ];then 345 | jp_error "cannot pop an empty stack" || return 346 | elif [ $JP_STACKSIZE -eq 1 ];then 347 | JP_OUT="${JP_STACK:0:-2}" 348 | JP_STACK= 349 | else 350 | JP_OUT="${JP_STACK%%$JP_SEP*}" 351 | JP_STACK="${JP_STACK#*$JP_SEP}" 352 | fi 353 | JP_STACKSIZE=$(( JP_STACKSIZE - 1 )) 354 | } 355 | 356 | jp_dup () { 357 | [ $JP_STACKSIZE -gt 0 ] || jp_error "dup needs one item on the stack" || return 358 | jp_pop 359 | jp_push "$JP_OUT " 360 | jp_push "$JP_OUT " 361 | } 362 | 363 | jp_over () { 364 | [ $JP_STACKSIZE -gt 1 ] || jp_error 'over needs two items on the stack' || return 365 | jp_swap 366 | jp_dup 367 | jp_pop 368 | local over_buf="$JP_OUT" 369 | jp_swap 370 | jp_push "$over_buf " 371 | } 372 | 373 | jp_swap () { 374 | [ $JP_STACKSIZE -gt 1 ] || jp_error 'swap needs two items on the stack' || return 375 | jp_pop 376 | local swap_buf="$JP_OUT" 377 | jp_pop 378 | jp_push "$swap_buf " 379 | jp_push "$JP_OUT " 380 | } 381 | 382 | jp_rot () { 383 | [ $JP_STACKSIZE -gt 2 ] || jp_error 'rot needs three items on the stack' || return 384 | jp_pop 385 | local rot_buf="$JP_OUT" 386 | jp_swap 387 | jp_push "$rot_buf " 388 | jp_swap 389 | } 390 | 391 | jp_uniq () { 392 | if jp__is_obj;then 393 | jp_pop || return 394 | if [ "${#JP_OUT}" -eq 3 ];then 395 | jp_push "$JP_OUT " 396 | return 397 | fi 398 | local flipflop=0 nestcnt=0 keys="" skip= rv="{ " sep= 399 | for t in ${JP_OUT:2:-2};do 400 | if [ $flipflop -eq 0 ];then # key 401 | if [[ "$keys" =~ "$t" ]];then 402 | skip=1 403 | else 404 | keys+="$t" 405 | rv+="$sep$t " 406 | sep=", " 407 | fi 408 | flipflop=$(( flipflop + 1 )) 409 | elif [ $flipflop -eq 1 ];then # : 410 | flipflop=$(( flipflop + 1 )) 411 | [ $skip ] || rv+="$t " 412 | elif [ $flipflop -eq 2 ];then # val 413 | [[ $t == [\[{] ]] && nestcnt=$(( nestcnt + 1 )) 414 | [[ $t == [\]}] ]] && nestcnt=$(( nestcnt - 1 )) 415 | if [ $nestcnt -eq 0 ];then 416 | flipflop=$(( flipflop + 1 )) 417 | fi 418 | [ $skip ] || rv+="$t " 419 | else # , 420 | flipflop=0 421 | skip= 422 | fi 423 | done 424 | jp_push "$rv} " 425 | else 426 | jp_error "uniq only works on objects" || return 427 | fi 428 | } 429 | 430 | jp_k () { 431 | if jp__is_obj;then 432 | jp_pop || return 433 | if [ "${#JP_OUT}" -eq 3 ];then 434 | jp_error "k doesn't work on an empty object" || return 435 | fi 436 | for t in ${JP_OUT:2:-2};do 437 | jp_push "$t " 438 | break 439 | done 440 | else 441 | jp_error "k only works on objects" || return 442 | fi 443 | } 444 | 445 | jp_v () { 446 | if jp__is_obj;then 447 | jp_pop || return 448 | if [ "${#JP_OUT}" -eq 3 ];then 449 | jp_error "v doesn't work on an empty object" || return 450 | fi 451 | local flipflop=0 nestcnt=0 rv= 452 | for t in ${JP_OUT:2:-2};do 453 | if [ $flipflop -eq 0 ];then # key 454 | flipflop=$(( flipflop + 1 )) 455 | elif [ $flipflop -eq 1 ];then # : 456 | flipflop=$(( flipflop + 1 )) 457 | else #v 458 | [[ $t == [\[{] ]] && nestcnt=$(( nestcnt + 1 )) 459 | [[ $t == [\]}] ]] && nestcnt=$(( nestcnt - 1 )) 460 | rv+="$t " 461 | if [ $nestcnt -eq 0 ];then 462 | jp_push "$rv" 463 | return 464 | fi 465 | fi 466 | done 467 | else 468 | jp_error "v only works on objects" || return 469 | fi 470 | } 471 | 472 | jp_len () { 473 | if jp__is_arr;then 474 | jp_pop || return 475 | local nestcnt=0 i=0 476 | if [ "${#JP_OUT}" -gt 3 ];then 477 | for t in ${JP_OUT:2:-2};do 478 | [[ $t == [\[{] ]] && nestcnt=$(( nestcnt + 1 )) 479 | [[ $t == [\]}] ]] && nestcnt=$(( nestcnt - 1 )) 480 | [ $nestcnt -eq 0 ]&&[ "$t" != ',' ]&&(( i++ )) 481 | done 482 | fi 483 | jp_push "$i " 484 | else 485 | jp_error "len only works on arrays" || return 486 | fi 487 | } 488 | 489 | jp_h () { 490 | if jp__is_arr;then 491 | jp_pop || return 492 | if [ "${#JP_OUT}" -eq 3 ];then 493 | jp_error "h doesn't work on an empty array" || return 494 | fi 495 | local nestcnt=0 rv= 496 | for t in ${JP_OUT:2:-2};do 497 | [[ $t == [\[{] ]] && nestcnt=$(( nestcnt + 1 )) 498 | [[ $t == [\]}] ]] && nestcnt=$(( nestcnt - 1 )) 499 | rv+="$t " 500 | if [ $nestcnt -eq 0 ];then 501 | jp_push "$rv" 502 | return 503 | fi 504 | done 505 | else 506 | jp_error "h only works on arrays" || return 507 | fi 508 | } 509 | 510 | jp_t () { 511 | if jp__is_arr;then 512 | jp_pop || return 513 | if [ "${#JP_OUT}" -eq 3 ];then 514 | jp_error "t doesn't work on an empty array" || return 515 | fi 516 | local nestcnt=0 rv='[ ' i=0 517 | for t in ${JP_OUT:2:-2};do 518 | [[ $t == [\[{] ]] && nestcnt=$(( nestcnt + 1 )) 519 | [[ $t == [\]}] ]] && nestcnt=$(( nestcnt - 1 )) 520 | (( i > 1 )) && rv+="$t " 521 | [ $nestcnt -eq 0 ] && (( i++ )) 522 | done 523 | jp_push "$rv] " 524 | else 525 | jp_error "t only works on arrays" || return 526 | fi 527 | } 528 | 529 | jp_concat () { 530 | local accum 531 | if jp__is_str;then 532 | jp_pop || return 533 | accum="\"${JP_OUT:1:$(("${#JP_OUT}"-2))}" 534 | jp__is_str || jp_error "concat expected a string but saw '${JP_STACK:0:1}'" || return 535 | jp_pop || return 536 | accum+="${JP_OUT:1:$(("${#JP_OUT}"-2))}\" " 537 | else 538 | if jp__is_arr;then 539 | jp_pop || return 540 | jp__is_arr || jp_error "concat expected an array but saw '${JP_STACK:0:1}'" || return 541 | elif jp__is_obj;then 542 | jp_pop || return 543 | jp__is_obj || jp_error "concat expected an object but saw '${JP_STACK:0:1}'" || return 544 | else 545 | jp_error "can only concat strings, arrays or objects" || return 546 | fi 547 | accum="${JP_OUT:0:-1}" 548 | jp_pop || return 549 | if [ "${#accum}" -eq 2 ];then # empty 550 | accum="$JP_OUT " 551 | elif [ "${#JP_OUT}" -eq 3 ];then # empty 552 | accum+="${JP_OUT:2:1} " 553 | else 554 | accum+=",${JP_OUT:1} " 555 | fi 556 | fi 557 | jp_push "$accum" 558 | } 559 | 560 | jp_collect () { 561 | local accum="[ " 562 | local sep 563 | while [ $JP_STACKSIZE -gt 0 ];do 564 | jp_pop || return 565 | accum+="$sep$JP_OUT " 566 | sep=", " 567 | done 568 | jp_push "$accum] " 569 | } 570 | 571 | jp__test () { 572 | local op_name="$1" num_op="$2" str_op="$3" right= 573 | if jp__is_str;then 574 | jp_pop || return 575 | right="$JP_OUT" 576 | if [ -z "$str_op" ];then 577 | jp_error "$op_name does not work on strings" || return 578 | elif jp__is_str;then 579 | jp_pop || return 580 | if [ "$JP_OUT" $str_op "$right" ];then 581 | jp_push "true " 582 | else 583 | jp_push "false " 584 | fi 585 | return 586 | fi 587 | elif jp__is_int;then 588 | jp_pop || return 589 | right="$JP_OUT" 590 | if jp__is_int;then 591 | jp_pop || return 592 | if [ $JP_OUT $num_op $right ];then 593 | jp_push "true " 594 | else 595 | jp_push "false " 596 | fi 597 | return 598 | fi 599 | fi 600 | jp_error "$op_name only works on pairs of strings or integers" || return 601 | } 602 | 603 | jp_count () { 604 | jp_push "$JP_STACKSIZE " 605 | } 606 | 607 | jp_is_obj () { 608 | if jp__is_obj;then 609 | jp_push 'true ' 610 | else 611 | jp_push 'false ' 612 | fi 613 | } 614 | 615 | jp_is_arr () { 616 | if jp__is_arr;then 617 | jp_push 'true ' 618 | else 619 | jp_push 'false ' 620 | fi 621 | 622 | } 623 | 624 | jp_is_bool () { 625 | if jp__is_bool;then 626 | jp_push 'true ' 627 | else 628 | jp_push 'false ' 629 | fi 630 | } 631 | 632 | jp_is_str () { 633 | if jp__is_str;then 634 | jp_push 'true ' 635 | else 636 | jp_push 'false ' 637 | fi 638 | } 639 | 640 | jp_is_num () { 641 | if jp__is_num;then 642 | jp_push 'true ' 643 | else 644 | jp_push 'false ' 645 | fi 646 | } 647 | 648 | jp_is_null () { 649 | if jp__is_null;then 650 | jp_push 'true ' 651 | else 652 | jp_push 'false ' 653 | fi 654 | } 655 | 656 | jp__is_obj () { 657 | [ -n "$JP_STACK" ]&&[ "${JP_STACK:0:1}" = '{' ] 658 | } 659 | 660 | jp__is_arr () { 661 | [ -n "$JP_STACK" ]&&[ "${JP_STACK:0:1}" = '[' ] 662 | } 663 | 664 | jp__is_bool () { 665 | jp__is_false || jp__is_true 666 | } 667 | 668 | jp__is_false () { 669 | [ -n "$JP_STACK" ]&&[ "${JP_STACK:0:1}" = 'f' ] 670 | } 671 | 672 | jp__is_true () { 673 | [ -n "$JP_STACK" ]&&[ "${JP_STACK:0:1}" = 't' ] 674 | } 675 | 676 | jp__is_str () { 677 | [ -n "$JP_STACK" ]&&[ "${JP_STACK:0:1}" = '"' ] 678 | } 679 | 680 | jp__is_num () { 681 | [ -n "$JP_STACK" ]&&[[ ${JP_STACK:0:1} =~ [[:digit:]-] ]] 682 | } 683 | 684 | jp__is_int () { 685 | [ -n "$JP_STACK" ]&&[[ "${JP_STACK%%$'\t\n'*}" =~ ^-?[0-9]+$ ]] 686 | } 687 | 688 | jp__is_null () { 689 | [ -n "$JP_STACK" ]&&[ "${JP_STACK:0:1}" = 'n' ] 690 | } 691 | 692 | jp_eq () { 693 | jp__test "eq" "-eq" "=" 694 | } 695 | 696 | jp_ne () { 697 | jp__test "ne" "-ne" "!=" 698 | } 699 | 700 | jp_gt () { 701 | jp__test "gt" "-gt" ">" 702 | } 703 | 704 | jp_ge () { 705 | jp__test "ge" "-ge" "" 706 | } 707 | 708 | jp_lt () { 709 | jp__test "lt" "-lt" "<" 710 | } 711 | 712 | jp_le () { 713 | jp__test "le" "-le" "" 714 | } 715 | 716 | jp_match () { 717 | if ! jp__is_str;then 718 | jp_error "match requires a string as a pattern" || return 719 | fi 720 | jp_pop || return 721 | local operand="${JP_OUT:1:$(( ${#JP_OUT} -2 ))}" 722 | if jp__is_str;then # remove " 723 | jp_pop || return 724 | if [[ "${JP_OUT:1:$(( ${#JP_OUT} -2 ))}" =~ $operand ]];then 725 | jp_push "true " 726 | else 727 | jp_push "false " 728 | fi 729 | elif jp__is_num;then 730 | jp_pop || return 731 | if [[ $JP_OUT =~ $operand ]];then 732 | jp_push "true " 733 | else 734 | jp_push "false " 735 | fi 736 | else 737 | jp_error "match only matches strings and nums" || return 738 | fi 739 | } 740 | 741 | jp__skip_next () { 742 | jp_next_arg || return 743 | if [ "$JP_ARG" = '.do' ];then 744 | local last_skip=$JP_SKIP 745 | JP_SKIP=1 746 | jp_eval "$JP_ARG" || return 747 | JP_SKIP=$last_skip 748 | fi 749 | } 750 | 751 | jp_if () { 752 | if jp__is_false;then 753 | jp_pop || return 754 | jp__skip_next || return 755 | jp_peek_arg 756 | if [ "$JP_PEEK" = '.else' ];then 757 | jp_next_arg || return 758 | fi 759 | elif jp__is_true;then 760 | jp_pop || return 761 | jp_next_arg || return 762 | jp_eval "$JP_ARG" 763 | jp_peek_arg 764 | if [ "$JP_PEEK" = '.else' ];then 765 | jp_next_arg || return 766 | jp__skip_next || return 767 | fi 768 | else 769 | jp_error "if requires a bool" || return 770 | fi 771 | } 772 | 773 | jp_else () { 774 | jp_error "else can only be used with if" || return 775 | } 776 | 777 | jp_do () { 778 | jp_next_arg || return 779 | while [ "$JP_ARG" != ".done" ];do 780 | [ $JP_SKIP ] || jp_eval "$JP_ARG" || return 781 | jp_next_arg || return 782 | done 783 | } 784 | 785 | jp_done () { 786 | jp_error "done can only be used with do" || return 787 | } 788 | 789 | jp_map () { 790 | if jp__is_obj;then 791 | jp_pop || return 792 | if [ "${#JP_OUT}" -gt 3 ];then 793 | local obj="$JP_OUT" flipflop=0 nestcnt=0 args_idx=$JP_ARGS_IDX accum 794 | for t in ${obj:2:-2};do 795 | if [ $flipflop -eq 0 ];then # key 796 | accum="{ $t : " 797 | flipflop=$(( flipflop + 1 )) 798 | elif [ $flipflop -eq 1 ];then # : 799 | flipflop=$(( flipflop + 1 )) 800 | elif [ $flipflop -eq 2 ];then # val 801 | accum+="$t " 802 | [[ $t == [\[{] ]] && nestcnt=$(( nestcnt + 1 )) 803 | [[ $t == [\]}] ]] && nestcnt=$(( nestcnt - 1 )) 804 | if [ $nestcnt -eq 0 ];then 805 | flipflop=$(( flipflop + 1 )) 806 | jp_push "$accum} " 807 | accum= 808 | JP_ARGS_IDX=$args_idx 809 | jp_next_arg || return 810 | jp_eval "$JP_ARG" || return 811 | fi 812 | else # , 813 | flipflop=0 814 | fi 815 | done 816 | else 817 | jp__skip_next 818 | fi 819 | elif jp__is_arr;then 820 | jp_pop || return 821 | if [ "${#JP_OUT}" -gt 3 ];then 822 | local nestcnt=0 args_idx=$JP_ARGS_IDX accum 823 | for t in ${JP_OUT:2:-2};do 824 | if [ $nestcnt -gt 0 ] || [ "$t" != ',' ];then 825 | accum+="$t " 826 | [[ $t == [\[{] ]] && nestcnt=$(( nestcnt + 1 )) 827 | [[ $t == [\]}] ]] && nestcnt=$(( nestcnt - 1 )) 828 | if [ $nestcnt -eq 0 ];then 829 | jp_push "$accum" 830 | accum= 831 | JP_ARGS_IDX=$args_idx 832 | jp_next_arg || return 833 | jp_eval "$JP_ARG" || return 834 | fi 835 | fi 836 | done 837 | else 838 | jp__skip_next 839 | fi 840 | else 841 | jp_error "can only map objects or arrays" || return 842 | fi 843 | } 844 | 845 | jp_cons () { 846 | jp_pop || return 847 | local val="$JP_OUT" 848 | jp__is_arr || jp_error "can only cons a value to an array" || return 849 | jp_pop || return 850 | if [ "${#JP_OUT}" -eq 3 ];then # empty 851 | jp_push "[ $val ] " 852 | else 853 | jp_push "[ $val , ${JP_OUT:2} " 854 | fi 855 | } 856 | 857 | jp_def () { 858 | jp_next_arg || return 859 | [ "${JP_ARG:0:1}" = '.' ] || jp_error "can only def names beginning with ." || return 860 | local name="jp_${JP_ARG:1}" args argc=1 nestcnt=0 861 | jp_next_arg || return 862 | args+="'$JP_ARG' " 863 | if [ "$JP_ARG" = '.do' ];then 864 | (( nestcnt++ )) 865 | while [ $nestcnt -gt 0 ];do 866 | jp_next_arg || return 867 | args+="'$JP_ARG' " 868 | ((argc++)) 869 | [ "$JP_ARG" = '.do' ] && ((nestcnt++)) 870 | [ "$JP_ARG" = '.done' ] && ((nestcnt--)) 871 | done 872 | fi 873 | type -t $name &>/dev/null && return # don't redefine functions 874 | eval $"$name () { JP_ARGS_LEN=\$((JP_ARGS_LEN+$argc-1));((JP_ARGS_IDX--));JP_ARGS=(\${JP_ARGS[@]:0:\$JP_ARGS_IDX} $args \${JP_ARGS[@]:\$((JP_ARGS_IDX+1))}); jp_next_arg || return;jp_eval \"\$JP_ARG\" || return; }" 875 | } 876 | 877 | jp_q () { 878 | JP_QUOTE=1 879 | } 880 | 881 | jp_nq () { 882 | JP_QUOTE= 883 | } 884 | 885 | jp_ex () { 886 | jp__is_int || jp_error "ex requires an arg count as an integer" || return 887 | jp_pop || return 888 | [ $JP_OUT -gt 0 ] || jp_error "ex arg count must be positive" || return 889 | local argc=$JP_OUT args= 890 | while (( argc-- ));do 891 | jp_pop || return 892 | args="${JP_OUT:1:-1} $args" 893 | done 894 | while IFS= read -r;do 895 | jp_eval "\"$REPLY\"" 896 | done < <(eval ${args[@]}) 897 | } 898 | 899 | jp_fromstr () { 900 | jp__is_str || jp_error "fromstr requires a string arg" || return 901 | jp_pop || return 902 | jp_eval "${JP_OUT:1:-1}" # strip quotes 903 | } 904 | 905 | jp_pair () { 906 | jp__is_str || jp_error "pair requires a string arg" || return 907 | jp_pop || return 908 | local k="$JP_OUT" 909 | jp_pop || return 910 | jp_push "{ $k : $JP_OUT } " 911 | } 912 | 913 | jp_idx () { 914 | if jp__is_int;then 915 | jp_pop || return 916 | if jp__is_arr;then 917 | [ $JP_OUT -ge 0 ] || jp_error "idx must be positive" || return 918 | local i=$JP_OUT j=0 919 | jp_pop || return 920 | if [ "${#JP_OUT}" -gt 3 ];then 921 | local nestcnt=0 accum 922 | for t in ${JP_OUT:2:-2};do 923 | [ $nestcnt -eq 0 ]&&[ "$t" = ',' ]&& continue 924 | [ "$i" -eq "$j" ] && accum+="$t " 925 | [[ $t == [\[{] ]] && nestcnt=$(( nestcnt + 1 )) 926 | [[ $t == [\]}] ]] && nestcnt=$(( nestcnt - 1 )) 927 | [ $nestcnt -eq 0 ]&&(( j++ )) 928 | (( j > i )) && break 929 | done 930 | [ -n "$accum" ] && jp_push "$accum" 931 | fi 932 | return 933 | fi 934 | fi 935 | jp_error "idx requires an int and an array" || return 936 | } 937 | 938 | jp_keyval () { 939 | if jp__is_str;then 940 | jp_pop || return 941 | if jp__is_obj;then 942 | local k="$JP_OUT" 943 | jp_pop || return 944 | if [ "${#JP_OUT}" -gt 3 ];then 945 | local obj="$JP_OUT" flipflop=0 nestcnt=0 accum match 946 | for t in ${obj:2:-2};do 947 | if [ $flipflop -eq 0 ];then # key 948 | [ "$k" = "$t" ] && match=1 949 | flipflop=$(( flipflop + 1 )) 950 | elif [ $flipflop -eq 1 ];then # : 951 | flipflop=$(( flipflop + 1 )) 952 | elif [ $flipflop -eq 2 ];then # val 953 | [ -n "$match" ] && accum+="$t " 954 | [[ $t == [\[{] ]] && nestcnt=$(( nestcnt + 1 )) 955 | [[ $t == [\]}] ]] && nestcnt=$(( nestcnt - 1 )) 956 | if [ $nestcnt -eq 0 ];then 957 | flipflop=$(( flipflop + 1 )) 958 | [ -n "$match" ] && break 959 | fi 960 | else # , 961 | flipflop=0 962 | fi 963 | done 964 | [ -n "$match" ] && jp_push "$accum" 965 | fi 966 | return 967 | fi 968 | fi 969 | jp_error "keyval requires a string and an object" || return 970 | } 971 | # END TRANSFORM FUNCTIONS 972 | 973 | # BEGIN PRINT FUNCTIONS 974 | jp_prettyprint () { 975 | while [ $JP_STACKSIZE -gt 0 ];do 976 | jp_pop || return 977 | local indentlen=${#JP_INDENT} 978 | local indent= 979 | local linebuf= 980 | for token in $JP_OUT;do 981 | case $token in 982 | [\[{]) if [ "${linebuf: -1}" = '[' ];then 983 | echo -E "$linebuf" 984 | linebuf="$indent$token" 985 | elif [[ "$linebuf" == *[^[:blank:]]* ]];then 986 | linebuf="$linebuf$token" 987 | else 988 | linebuf="$indent$token" 989 | fi 990 | indent="$indent$JP_INDENT" 991 | ;; 992 | [\]}]) [[ -n "$indent" ]] && indent="${indent:$indentlen}" 993 | if [[ "$linebuf" == *[^[:blank:]] ]];then 994 | if [[ "${linebuf:$((${#linebuf}-1)):1}" == [\[{] ]];then 995 | linebuf="$linebuf$token" 996 | else 997 | echo -E "$linebuf" 998 | linebuf="$indent$token" 999 | fi 1000 | else 1001 | linebuf="$indent$token" 1002 | fi 1003 | ;; 1004 | ',') echo -E "$linebuf," 1005 | linebuf="$indent";; 1006 | ':') linebuf="$linebuf: ";; 1007 | *) if [[ "$linebuf" == *[^[:blank:]] ]];then 1008 | echo -E "$linebuf" 1009 | linebuf="$indent$token" 1010 | else 1011 | linebuf="$linebuf$token" 1012 | fi 1013 | esac 1014 | done 1015 | [[ "$linebuf" == *[^[:blank:]]* ]] && echo -E "$linebuf" 1016 | done 1017 | } 1018 | 1019 | jp_plainprint () { 1020 | while [ $JP_STACKSIZE -gt 0 ];do 1021 | jp_pop || return 1022 | for t in $JP_OUT;do 1023 | echo -nE "$t" 1024 | done 1025 | echo 1026 | done 1027 | } 1028 | # END PRINT FUNCTIONS 1029 | 1030 | # BEGIN MAIN 1031 | jp_next_arg () { 1032 | (( JP_ARGS_IDX < JP_ARGS_LEN )) || jp_error "ran out of args" || return 1033 | JP_ARG="${JP_ARGS[$((JP_ARGS_IDX))]}" 1034 | (( JP_ARGS_IDX++ )) 1035 | return 0 1036 | } 1037 | 1038 | jp_peek_arg () { 1039 | JP_PEEK="${JP_ARGS[$((JP_ARGS_IDX))]}" 1040 | } 1041 | 1042 | jp_eval () { 1043 | case "$1" in 1044 | [.]*) # transformation command 1045 | eval "jp_${1#.}" || return;; 1046 | *) # json to parse 1047 | if [ $JP_QUOTE ] && [ ${1:0:1} != '"' ];then 1048 | set -- "\"$1\"" 1049 | fi 1050 | JP_IDX=0 1051 | JP_LINE=1 1052 | JP_BUF="$1" 1053 | JP_BUF_MAXLEN="${#JP_BUF}" 1054 | jp_parse_json || return 1055 | jp_push "$JP_TOKENS";; 1056 | esac 1057 | } 1058 | 1059 | jp_run () { 1060 | JP_STACKSIZE=0 1061 | # parse 1062 | if [ $JP_INPUT ];then 1063 | jp_parse_json || return 1064 | jp_push "$JP_TOKENS" 1065 | fi 1066 | 1067 | # transform 1068 | if [ $JP_DEBUG ];then 1069 | echo -e "DEBUG: \033[1ms\033[0m:step, \033[1mn\033[0m:next arg, \033[1mq\033[0m:quit" 1070 | trap 'jp_debug "${BASH_COMMAND%% *}"' DEBUG 1071 | set -T 1072 | fi 1073 | local in_idx="$JP_IDX" in_line="$JP_LINE" # save stdin parse state 1074 | JP_LINE=1 1075 | while (( JP_ARGS_IDX < JP_ARGS_LEN ));do 1076 | jp_next_arg || return 1077 | jp_eval "$JP_ARG" || return 1078 | done 1079 | JP_IDX="$in_idx" # restore stdin parse state 1080 | JP_LINE="$in_line" 1081 | [ $JP_DEBUG ]&&trap '' DEBUG 1082 | 1083 | # print 1084 | [ $JP_SILENT ] && return 0 1085 | if [ $JP_PRETTY ];then 1086 | jp_prettyprint 1087 | else 1088 | jp_plainprint 1089 | fi 1090 | return 0 1091 | } 1092 | 1093 | jp_load_macros () { 1094 | [ -f "$1" ] || jp_error "cannot find macro file: $1" || return 1095 | [ -r "$1" ] || jp_error "cannot open macro file for reading: $1" || return 1096 | JP_LINE=1 1097 | while IFS= read -r;do 1098 | jp_macro_to_args "$REPLY" || return 1099 | JP_ARGS_LEN=${#JP_ARGS[@]} 1100 | JP_ARGS_IDX=0 1101 | jp_next_arg || return 1102 | jp_eval "$JP_ARG" || return 1103 | (( JP_LINE++ )) 1104 | done < "$1" 1105 | } 1106 | 1107 | # this silly function is needed to avoid splitting strings on whitespace 1108 | jp_macro_to_args () { 1109 | local del=" " quo='"' esc="\\" len="${#1}" idx=0 cnt=0 word= 1110 | JP_ARGS=() 1111 | while (( idx <= len ));do 1112 | c="${1:$idx:1}" 1113 | (( idx++ )) 1114 | if [ $cnt -eq 0 ];then 1115 | if [ -z "$c" ] || [ "$c" = "$del" ];then 1116 | if [ -n "$word" ];then 1117 | JP_ARGS+=("$word") 1118 | word= 1119 | fi 1120 | continue 1121 | elif [ "$c" = "$quo" ];then 1122 | (( cnt++ )) 1123 | fi 1124 | elif [ -z "$c" ];then 1125 | jp_error "found unterminated string in macro: col:$idx, $1" || return 1126 | elif [ "$c" = "$quo" ];then 1127 | [ "${word: -1}" != "$esc" ] && (( cnt-- )) 1128 | fi 1129 | word+="$c" 1130 | done 1131 | } 1132 | 1133 | jp_main () { 1134 | JP_INDENT=" " # 2 space indent default 1135 | [ -t 1 ] && JP_PRETTY=1 # default to pretty for a tty 1136 | [ -t 0 ] || JP_INPUT=1 # read input if being piped 1137 | while getopts "dh:HpPrsi:m:" opt;do 1138 | case "$opt" in 1139 | 'd') JP_DEBUG=1;; 1140 | 'h') JP_HISTORY="$OPTARG";; 1141 | 'H') JP_HISTORY=;; 1142 | 'p') JP_PRETTY=1;; 1143 | 'P') JP_PRETTY=;; 1144 | 'i') JP_INDENT="$OPTARG";; 1145 | 'r') JP_REPL=1;; 1146 | 's') JP_SILENT=1;; 1147 | 'm') jp_load_macros "$OPTARG" || return 1148 | esac 1149 | done 1150 | shift $((OPTIND-1)) # reset options processing 1151 | if [ $JP_REPL ];then 1152 | jp_repl 1153 | exit 1154 | fi 1155 | [ $JP_INPUT ] && jp_readline 1156 | while :;do 1157 | JP_ARGS=("$@") 1158 | JP_ARGS_LEN=${#JP_ARGS[@]} 1159 | JP_ARGS_IDX=0 1160 | jp_run || return 1161 | if [ $JP_INPUT ];then 1162 | jp_readline && [ $JP_BUF_MAXLEN -eq 0 ] && break # no more input 1163 | else 1164 | break 1165 | fi 1166 | done 1167 | return 0 1168 | } 1169 | 1170 | jp_repl () { 1171 | history -r "$JP_HISTORY" 1172 | local msg="Welcome to the jp REPL. Type commands and ENTER to evaluate, q quits." 1173 | JP_ERROR="$msg" 1174 | jp_redraw 1175 | while IFS= read -e -p '> ' -r;do 1176 | if [ "$REPLY" = 'q' ];then 1177 | echo -ne "\e[H\e[JGoodbye.\n" 1178 | break 1179 | fi 1180 | jp_macro_to_args "$REPLY" || return 1181 | JP_ARGS_LEN=${#JP_ARGS[@]} 1182 | JP_ARGS_IDX=0 1183 | while (( JP_ARGS_IDX < JP_ARGS_LEN ));do 1184 | jp_next_arg || break 1185 | jp_eval "$JP_ARG" || break 1186 | done 1187 | [ "${JP_ERROR:0:7}" = 'Welcome' ]&&history -s "$REPLY" 1188 | jp_redraw 1189 | JP_ERROR="$msg" 1190 | done 1191 | history -w "$JP_HISTORY" 1192 | } 1193 | 1194 | jp_redraw () { 1195 | echo -en '\e[H\e[J\e[3H' 1196 | jp_dump 1197 | echo -en "\e[H$JP_ERROR\n" 1198 | } 1199 | 1200 | [ "$0" = "$BASH_SOURCE" ] && jp_main "$@" 1201 | # END MAIN 1202 | # vim: set ft=sh: 1203 | -------------------------------------------------------------------------------- /macros.jp: -------------------------------------------------------------------------------- 1 | .def .exists .do false .rot .map .do .k .rot .swap .over .eq .rot .or .done .swap .pop .done 2 | .def .not .do .if false .else true .done 3 | .def .and .do .if .do .if true .else false .done .else .do .pop false .done .done 4 | .def .or .do .if .do .pop true .done .else .do .if true .else false .done .done 5 | .def .revarr .do [] .swap .map .cons .done 6 | .def .revobj .do {} .swap .map .concat .done 7 | .def .rev .do .is_obj .if .revobj .else .revarr .done 8 | .def .empty .do .count 0 .eq .done 9 | .def .ltarr .do [] .rot .rot .swap .map .do .over .over .swap .lt .if .do .rot .swap .cons .swap .done .else .pop .done .pop .revarr .done 10 | .def .gtarr .do [] .rot .rot .swap .map .do .over .over .swap .gt .if .do .rot .swap .cons .swap .done .else .pop .done .pop .revarr .done 11 | .def .eqarr .do [] .rot .rot .swap .map .do .over .over .swap .eq .if .do .rot .swap .cons .swap .done .else .pop .done .pop .done 12 | .def .ht .do .dup .t .swap .h .done 13 | .def .sort .do .dup .len 1 .gt .if .do .dup .dup .ht .dup [] .swap .cons .rot .rot .gtarr .sort .swap .concat .swap .ht .eqarr .concat .swap .ht .ltarr .sort .concat .done .done 14 | .def .ab .do .over .over .gt .if .swap .pop .done 15 | .def .updateobj .do {} .swap .rot .map .do .over .k .over .k .eq .if .do .pop .dup .done .rot .concat .swap .done .pop .done 16 | .def .upsertobj .do .concat .uniq .done 17 | .def .deleteobj .do {} .swap .rot .map .do .over .over .k .eq .if .pop .else .do .rot .concat .swap .done .done .pop .done 18 | .def .filterobj .do {} .swap .rot .map .do .over .over .k .ne .if .pop .else .do .rot .concat .swap .done .done .pop .done 19 | -------------------------------------------------------------------------------- /test-bootstrap.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source jp 3 | JP_TEST_COUNT=0 4 | JP_TEST_FAIL_COUNT=0 5 | 6 | function ok { 7 | (( JP_TEST_COUNT++ )) 8 | if [[ "$1" != 1 ]];then 9 | (( JP_TEST_FAIL_COUNT++ )) 10 | echo -n "not " 11 | fi 12 | echo "ok $JP_TEST_COUNT $2" 13 | } 14 | 15 | function pass { 16 | (( JP_TEST_COUNT++ )) 17 | echo "ok $JP_TEST_COUNT $1" 18 | } 19 | 20 | function fail { 21 | (( JP_TEST_COUNT++ )) 22 | (( JP_TEST_FAIL_COUNT++ )) 23 | echo "not ok $JP_TEST_COUNT $1" 24 | } 25 | 26 | function skip { 27 | pass "# SKIP $1" 28 | } 29 | 30 | function todo { 31 | (( JP_TEST_COUNT++ )) 32 | echo "not ok $JP_TEST_COUNT # TODO $1" 33 | } 34 | 35 | function end { 36 | echo "1..$JP_TEST_COUNT" 37 | exit "$JP_TEST_FAIL_COUNT" 38 | } 39 | -------------------------------------------------------------------------------- /tests/parse/array.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | 4 | function test_good_token { 5 | JP_IDX=0 6 | JP_LINE=1 7 | JP_BUF=('["octocat","atom","electron","api"]') 8 | JP_BUF_MAXLEN="${#JP_BUF}" 9 | jp_chomp 10 | jp_array 11 | if [ "${JP_TOKENS:0:1}" = '[' ];then 12 | pass "parse opening bracket token" 13 | else 14 | fail "parse opening bracket token" 15 | fi 16 | if [ ${JP_TOKENS:2:9} = '"octocat"' ];then 17 | pass "parse first member token" 18 | else 19 | fail "parse first member token failed: '${JP_TOKENS:2:8}'" 20 | fi 21 | if [ ${JP_TOKENS:36:5} = '"api"' ];then 22 | pass "parse last member token" 23 | else 24 | fail "parse last member token failed: '${JP_TOKENS:37:5}'" 25 | fi 26 | if [ ${JP_TOKENS:42:1} = ']' ];then 27 | pass "parse closing bracket token" 28 | else 29 | fail "parse closing bracket token" 30 | fi 31 | } 32 | 33 | function test_unclosed { 34 | JP_IDX=0 35 | JP_LINE=1 36 | JP_BUF=('[') 37 | JP_BUF_MAXLEN="${#JP_BUF}" 38 | jp_chomp 39 | jp_array 2> /dev/null # silence the error msg 40 | ok $(( $? == 1 )) "parse '[' is an error" 41 | } 42 | 43 | function test_trailing_comma { 44 | JP_IDX=0 45 | JP_LINE=1 46 | JP_BUF=('[1,') 47 | JP_BUF_MAXLEN="${#JP_BUF}" 48 | jp_chomp 49 | jp_array 2> /dev/null # silence the error msg 50 | ok $(( $? == 1 )) "parse '[,' is an error" 51 | } 52 | 53 | function test_leading_comma { 54 | JP_IDX=0 55 | JP_LINE=1 56 | JP_BUF=('[,') 57 | JP_BUF_MAXLEN="${#JP_BUF}" 58 | jp_chomp 59 | jp_array 2> /dev/null # silence the error msg 60 | ok $(( $? == 1 )) "parse '[1,' is an error" 61 | } 62 | 63 | test_good_token 64 | test_unclosed 65 | test_leading_comma 66 | test_trailing_comma 67 | end 68 | -------------------------------------------------------------------------------- /tests/parse/halts.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source test-bootstrap.bash 3 | 4 | if [ -z "$JP_TEST_SLOW" ];then 5 | skip "slow tests disabled" 6 | else 7 | cat tests/share/ec2-describe-instances.json | ./jp -s 8 | ok $(( $? == 0 )) "jp didn't halt on large input" 9 | fi 10 | 11 | end 12 | -------------------------------------------------------------------------------- /tests/parse/json-test-suite.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | 4 | jp_slow_tests=( \ 5 | n_structure_100000_opening_arrays.json \ 6 | n_structure_open_array_object.json ) 7 | 8 | function is_slow_test { 9 | for st in ${jp_slow_tests[@]};do 10 | [ "$1" = "$st" ] && return 0 11 | done 12 | return 1 13 | } 14 | 15 | jp_todo_tests=( \ 16 | n_multidigit_number_then_00.json \ 17 | n_string_unescaped_crtl_char.json \ 18 | n_string_unescaped_newline.json \ 19 | n_structure_null-byte-outside-string.json \ 20 | ) 21 | 22 | function is_todo_test { 23 | for st in ${jp_todo_tests[@]};do 24 | [ "$1" = "$st" ] && return 0 25 | done 26 | return 1 27 | } 28 | 29 | function test_parse_pass { 30 | local filepath="$1" filename="$2" 31 | if [ -z "$JP_TEST_SLOW" ] && is_slow_test "$filename";then 32 | skip "$filepath" 33 | return 34 | fi 35 | $(cat "$filepath" | ./jp -s 2>/dev/null) 36 | if [ $? -eq 0 ];then 37 | pass "$filename parses as expected" 38 | else 39 | fail "$filename unexpectedly fails to parse" 40 | fi 41 | } 42 | 43 | for file in tests/share/JSONTestSuite/test_parsing/y_*;do 44 | test_parse_pass "$file" "${file##*/}" 45 | done 46 | 47 | function test_parse_fail { 48 | local filepath="$1" filename="$2" 49 | if [ -z "$JP_TEST_SLOW" ] && is_slow_test "$filename";then 50 | skip "$filename" 51 | return 52 | fi 53 | if is_todo_test "$filename";then 54 | todo "$filename jp does not detect null bytes" 55 | return 56 | fi 57 | $(cat "$filepath" | ./jp -s 2>/dev/null) 58 | if [ $? -gt 0 ];then 59 | pass "$filename fails to parses as expected" 60 | else 61 | fail "$filename unexpectedly parses" 62 | fi 63 | } 64 | 65 | for file in tests/share/JSONTestSuite/test_parsing/n_*;do 66 | test_parse_fail "$file" "${file##*/}" 67 | done 68 | 69 | function test_parse_optional { 70 | local filepath="$1" filename="$2" result="pass" 71 | if [ -z "$JP_TEST_SLOW" ] && is_slow_test "$filename";then 72 | skip "$filename" 73 | return 74 | fi 75 | $(cat "$filepath" | ./jp -s 2>/dev/null) 76 | [ $? -gt 0 ] && result="fail" 77 | pass "$filename implementation $result" 78 | } 79 | 80 | for file in tests/share/JSONTestSuite/test_parsing/i_*;do 81 | test_parse_optional "$file" "${file##*/}" 82 | done 83 | 84 | end 85 | -------------------------------------------------------------------------------- /tests/parse/null.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | 4 | function test_good_token { 5 | JP_IDX=0 6 | JP_LINE=1 7 | JP_BUF='null' 8 | JP_BUF_MAXLEN="${#JP_BUF}" 9 | jp_chomp 10 | jp_null 11 | ok $(( "${JP_TOKENS[0]}" == "null" )) "parse 'null' token" 12 | } 13 | 14 | function test_bad_token { 15 | JP_IDX=0 16 | JP_LINE=1 17 | JP_BUF='nul' 18 | JP_BUF_MAXLEN="${#JP_BUF}" 19 | jp_chomp 20 | jp_null 2> /dev/null # silence the error msg 21 | ok $(( $? == 1 )) "parse 'nul' is an error" 22 | } 23 | 24 | test_good_token 25 | test_bad_token 26 | end 27 | -------------------------------------------------------------------------------- /tests/parse/string-unicode.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | 4 | function test_♥_token { 5 | JP_IDX=0 6 | JP_LINE=1 7 | JP_BUF='"\u2665"' 8 | JP_BUF_MAXLEN="${#JP_BUF}" 9 | jp_chomp 10 | jp_string 11 | ok $(( $? == 0 )) "parses '\u2665' without error" 12 | if [ "${JP_TOKENS:0:-1}" == '"\u2665"' ];then 13 | pass "parse unicode '♥' token" 14 | else 15 | fail "parse unicode '♥' token failed: '${JP_TOKENS:0:-1}'" 16 | fi 17 | } 18 | 19 | function test_too_short { 20 | JP_IDX=0 21 | JP_LINE=1 22 | JP_BUF='"\u265"' 23 | JP_BUF_MAXLEN="${#JP_BUF}" 24 | jp_chomp 25 | jp_string 2> /dev/null 26 | ok $(( $? == 1 )) "parse '\u266' is an error (escape too short)" 27 | } 28 | 29 | function test_capital_u { 30 | JP_IDX=0 31 | JP_LINE=1 32 | JP_BUF='"\U2665"' 33 | JP_BUF_MAXLEN="${#JP_BUF}" 34 | jp_chomp 35 | jp_string 2> /dev/null 36 | ok $(( $? == 1 )) "parse '\U26657' is an error (u is capitalized)" 37 | } 38 | 39 | test_♥_token 40 | test_too_short 41 | test_capital_u 42 | end 43 | -------------------------------------------------------------------------------- /tests/print/indent.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | expect=$'[\n\t1,\n\t2,\n\t3\n]' 6 | output=$(./jp -pi ' ' $expect) 7 | if [ "$output" = $expect ];then 8 | pass "-i forces indent to tab" 9 | else 10 | printf -v outputesc "%q" "$output" 11 | fail "-i doesn't force indent to tab: $outputesc" 12 | fi 13 | 14 | end 15 | -------------------------------------------------------------------------------- /tests/print/plain.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | expect='[1,2,3]' 6 | arrays=$(./jp $expect) 7 | if [ "$arrays" = $expect ];then 8 | pass "plain output is default on non-tty" 9 | else 10 | printf -v arraysesc "%q" "$arrays" 11 | fail "plain output is default on non-tty: $arraysesc" 12 | fi 13 | 14 | expect='[1,2,[3,4,{"a":5,"b":6}],7]' 15 | output=$(./jp -P $expect) 16 | if [ "$output" = $expect ];then 17 | pass "plain outputs as expected" 18 | else 19 | printf -v outputesc "%q" "$output" 20 | fail "plain doesn't output as expected: $outputesc" 21 | fi 22 | 23 | which socat 1>/dev/null # to simulate tty 24 | if [ $? -eq 0 ];then 25 | output=$(socat -u -t0 EXEC:"./jp -P $expect",pty -) 26 | if [ "$output" = $expect$'\r' ];then 27 | pass "-P forces plain output" 28 | else 29 | printf -v outputesc "%q" "$output" 30 | fail "-P doesn't force plain output: $outputesc" 31 | fi 32 | fi 33 | end 34 | -------------------------------------------------------------------------------- /tests/print/pretty.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | expect=$'[\n 1,\n 2,\n 3\n]' 6 | output=$(./jp -p $expect) 7 | if [ "$output" = $expect ];then 8 | pass "-p forces pretty output on non-tty" 9 | else 10 | printf -v outputesc "%q" "$output" 11 | fail "-p doesn't force pretty output on non-tty: $outputesc" 12 | fi 13 | 14 | expect=$'[\n 1,\n 2,\n [\n 3,\n 4,\n {\n "a": 5,\n "b": 6\n }\n ],\n 7\n]' 15 | output=$(./jp -p '[1,2,[3,4,{"a":5,"b":6}],7]') 16 | if [ "$output" = $expect ];then 17 | pass "pretty indents as expected" 18 | else 19 | printf -v outputesc "%q" "$output" 20 | fail "pretty doesn't indent as expected: $outputesc" 21 | fi 22 | 23 | which socat 1>/dev/null # to simulate tty 24 | if [ $? -eq 0 ];then 25 | expect=$'[\r\n 1,\r\n 2,\r\n 3\r\n]' 26 | output=$(socat -u -t0 EXEC:"./jp $expect",pty -) 27 | if [ "$output" = $expect$'\r' ];then 28 | pass "pretty is default on tty" 29 | else 30 | printf -v outputesc "%q" "$output" 31 | fail "pretty is not default on tty: $outputesc" 32 | fi 33 | fi 34 | end 35 | -------------------------------------------------------------------------------- /tests/print/silent.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | empty=$(./jp -s) 6 | if [ "$empty" = '' ];then 7 | pass "silent mode emits nothing with empty stack" 8 | else 9 | printf -v emptyesc "%q" "$empty" 10 | fail "silent mode emits nothing with empty stack: $emptyesc" 11 | fi 12 | 13 | arrays=$(cat tests/share/arrays.jsonp | ./jp -s) 14 | if [ "$arrays" = '' ];then 15 | pass "silent mode emits nothing with arrays stack" 16 | else 17 | printf -v arraysesc "%q" "$arrays" 18 | fail "silent mode emits nothing with arrays stack: $arraysesc" 19 | fi 20 | 21 | end 22 | -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_number_double_huge_neg_exp.json: -------------------------------------------------------------------------------- 1 | [123.456e-789] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_number_huge_exp.json: -------------------------------------------------------------------------------- 1 | [0.4e00669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_number_neg_int_huge_exp.json: -------------------------------------------------------------------------------- 1 | [-1e+9999] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_number_pos_double_huge_exp.json: -------------------------------------------------------------------------------- 1 | [1.5e+9999] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_number_real_neg_overflow.json: -------------------------------------------------------------------------------- 1 | [-123123e100000] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_number_real_pos_overflow.json: -------------------------------------------------------------------------------- 1 | [123123e100000] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_number_real_underflow.json: -------------------------------------------------------------------------------- 1 | [123e-10000000] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_number_too_big_neg_int.json: -------------------------------------------------------------------------------- 1 | [-123123123123123123123123123123] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_number_too_big_pos_int.json: -------------------------------------------------------------------------------- 1 | [100000000000000000000] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_number_very_big_negative_int.json: -------------------------------------------------------------------------------- 1 | [-237462374673276894279832749832423479823246327846] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_object_key_lone_2nd_surrogate.json: -------------------------------------------------------------------------------- 1 | {"\uDFAA":0} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_string_1st_surrogate_but_2nd_missing.json: -------------------------------------------------------------------------------- 1 | ["\uDADA"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_string_1st_valid_surrogate_2nd_invalid.json: -------------------------------------------------------------------------------- 1 | ["\uD888\u1234"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_string_UTF-16LE_with_BOM.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_parsing/i_string_UTF-16LE_with_BOM.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_string_UTF-8_invalid_sequence.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_parsing/i_string_UTF-8_invalid_sequence.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_string_UTF8_surrogate_U+D800.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_parsing/i_string_UTF8_surrogate_U+D800.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_string_incomplete_surrogate_and_escape_valid.json: -------------------------------------------------------------------------------- 1 | ["\uD800\n"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_string_incomplete_surrogate_pair.json: -------------------------------------------------------------------------------- 1 | ["\uDd1ea"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_string_incomplete_surrogates_escape_valid.json: -------------------------------------------------------------------------------- 1 | ["\uD800\uD800\n"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_string_invalid_lonely_surrogate.json: -------------------------------------------------------------------------------- 1 | ["\ud800"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_string_invalid_surrogate.json: -------------------------------------------------------------------------------- 1 | ["\ud800abc"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_string_invalid_utf-8.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_parsing/i_string_invalid_utf-8.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_string_inverted_surrogates_U+1D11E.json: -------------------------------------------------------------------------------- 1 | ["\uDd1e\uD834"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_string_iso_latin_1.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_parsing/i_string_iso_latin_1.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_string_lone_second_surrogate.json: -------------------------------------------------------------------------------- 1 | ["\uDFAA"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_string_lone_utf8_continuation_byte.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_parsing/i_string_lone_utf8_continuation_byte.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_string_not_in_unicode_range.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_parsing/i_string_not_in_unicode_range.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_string_overlong_sequence_2_bytes.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_parsing/i_string_overlong_sequence_2_bytes.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_string_overlong_sequence_6_bytes.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_parsing/i_string_overlong_sequence_6_bytes.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_string_overlong_sequence_6_bytes_null.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_parsing/i_string_overlong_sequence_6_bytes_null.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_string_truncated-utf-8.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_parsing/i_string_truncated-utf-8.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_string_utf16BE_no_BOM.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_parsing/i_string_utf16BE_no_BOM.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_string_utf16LE_no_BOM.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_parsing/i_string_utf16LE_no_BOM.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_structure_500_nested_arrays.json: -------------------------------------------------------------------------------- 1 | [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/i_structure_UTF-8_BOM_empty_object.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_1_true_without_comma.json: -------------------------------------------------------------------------------- 1 | [1 true] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_a_invalid_utf8.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_parsing/n_array_a_invalid_utf8.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_colon_instead_of_comma.json: -------------------------------------------------------------------------------- 1 | ["": 1] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_comma_after_close.json: -------------------------------------------------------------------------------- 1 | [""], -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_comma_and_number.json: -------------------------------------------------------------------------------- 1 | [,1] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_double_comma.json: -------------------------------------------------------------------------------- 1 | [1,,2] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_double_extra_comma.json: -------------------------------------------------------------------------------- 1 | ["x",,] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_extra_close.json: -------------------------------------------------------------------------------- 1 | ["x"]] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_extra_comma.json: -------------------------------------------------------------------------------- 1 | ["",] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_incomplete.json: -------------------------------------------------------------------------------- 1 | ["x" -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_incomplete_invalid_value.json: -------------------------------------------------------------------------------- 1 | [x -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_inner_array_no_comma.json: -------------------------------------------------------------------------------- 1 | [3[4]] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_invalid_utf8.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_parsing/n_array_invalid_utf8.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_items_separated_by_semicolon.json: -------------------------------------------------------------------------------- 1 | [1:2] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_just_comma.json: -------------------------------------------------------------------------------- 1 | [,] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_just_minus.json: -------------------------------------------------------------------------------- 1 | [-] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_missing_value.json: -------------------------------------------------------------------------------- 1 | [ , ""] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_newlines_unclosed.json: -------------------------------------------------------------------------------- 1 | ["a", 2 | 4 3 | ,1, -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_number_and_comma.json: -------------------------------------------------------------------------------- 1 | [1,] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_number_and_several_commas.json: -------------------------------------------------------------------------------- 1 | [1,,] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_spaces_vertical_tab_formfeed.json: -------------------------------------------------------------------------------- 1 | [" a"\f] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_star_inside.json: -------------------------------------------------------------------------------- 1 | [*] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_unclosed.json: -------------------------------------------------------------------------------- 1 | ["" -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_unclosed_trailing_comma.json: -------------------------------------------------------------------------------- 1 | [1, -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_unclosed_with_new_lines.json: -------------------------------------------------------------------------------- 1 | [1, 2 | 1 3 | ,1 -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_array_unclosed_with_object_inside.json: -------------------------------------------------------------------------------- 1 | [{} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_incomplete_false.json: -------------------------------------------------------------------------------- 1 | [fals] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_incomplete_null.json: -------------------------------------------------------------------------------- 1 | [nul] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_incomplete_true.json: -------------------------------------------------------------------------------- 1 | [tru] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_multidigit_number_then_00.json: -------------------------------------------------------------------------------- 1 | 123 2 | -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_++.json: -------------------------------------------------------------------------------- 1 | [++1234] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_+1.json: -------------------------------------------------------------------------------- 1 | [+1] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_+Inf.json: -------------------------------------------------------------------------------- 1 | [+Inf] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_-01.json: -------------------------------------------------------------------------------- 1 | [-01] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_-1.0..json: -------------------------------------------------------------------------------- 1 | [-1.0.] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_-2..json: -------------------------------------------------------------------------------- 1 | [-2.] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_-NaN.json: -------------------------------------------------------------------------------- 1 | [-NaN] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_.-1.json: -------------------------------------------------------------------------------- 1 | [.-1] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_.2e-3.json: -------------------------------------------------------------------------------- 1 | [.2e-3] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_0.1.2.json: -------------------------------------------------------------------------------- 1 | [0.1.2] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_0.3e+.json: -------------------------------------------------------------------------------- 1 | [0.3e+] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_0.3e.json: -------------------------------------------------------------------------------- 1 | [0.3e] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_0.e1.json: -------------------------------------------------------------------------------- 1 | [0.e1] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_0_capital_E+.json: -------------------------------------------------------------------------------- 1 | [0E+] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_0_capital_E.json: -------------------------------------------------------------------------------- 1 | [0E] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_0e+.json: -------------------------------------------------------------------------------- 1 | [0e+] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_0e.json: -------------------------------------------------------------------------------- 1 | [0e] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_1.0e+.json: -------------------------------------------------------------------------------- 1 | [1.0e+] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_1.0e-.json: -------------------------------------------------------------------------------- 1 | [1.0e-] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_1.0e.json: -------------------------------------------------------------------------------- 1 | [1.0e] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_1_000.json: -------------------------------------------------------------------------------- 1 | [1 000.0] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_1eE2.json: -------------------------------------------------------------------------------- 1 | [1eE2] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_2.e+3.json: -------------------------------------------------------------------------------- 1 | [2.e+3] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_2.e-3.json: -------------------------------------------------------------------------------- 1 | [2.e-3] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_2.e3.json: -------------------------------------------------------------------------------- 1 | [2.e3] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_9.e+.json: -------------------------------------------------------------------------------- 1 | [9.e+] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_Inf.json: -------------------------------------------------------------------------------- 1 | [Inf] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_NaN.json: -------------------------------------------------------------------------------- 1 | [NaN] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_U+FF11_fullwidth_digit_one.json: -------------------------------------------------------------------------------- 1 | [1] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_expression.json: -------------------------------------------------------------------------------- 1 | [1+2] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_hex_1_digit.json: -------------------------------------------------------------------------------- 1 | [0x1] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_hex_2_digits.json: -------------------------------------------------------------------------------- 1 | [0x42] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_infinity.json: -------------------------------------------------------------------------------- 1 | [Infinity] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_invalid+-.json: -------------------------------------------------------------------------------- 1 | [0e+-1] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_invalid-negative-real.json: -------------------------------------------------------------------------------- 1 | [-123.123foo] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_invalid-utf-8-in-bigger-int.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_parsing/n_number_invalid-utf-8-in-bigger-int.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_invalid-utf-8-in-exponent.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_parsing/n_number_invalid-utf-8-in-exponent.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_invalid-utf-8-in-int.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_parsing/n_number_invalid-utf-8-in-int.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_minus_infinity.json: -------------------------------------------------------------------------------- 1 | [-Infinity] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_minus_sign_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | [-foo] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_minus_space_1.json: -------------------------------------------------------------------------------- 1 | [- 1] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_neg_int_starting_with_zero.json: -------------------------------------------------------------------------------- 1 | [-012] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_neg_real_without_int_part.json: -------------------------------------------------------------------------------- 1 | [-.123] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_neg_with_garbage_at_end.json: -------------------------------------------------------------------------------- 1 | [-1x] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_real_garbage_after_e.json: -------------------------------------------------------------------------------- 1 | [1ea] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_real_with_invalid_utf8_after_e.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_parsing/n_number_real_with_invalid_utf8_after_e.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_real_without_fractional_part.json: -------------------------------------------------------------------------------- 1 | [1.] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_starting_with_dot.json: -------------------------------------------------------------------------------- 1 | [.123] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_with_alpha.json: -------------------------------------------------------------------------------- 1 | [1.2a-3] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_with_alpha_char.json: -------------------------------------------------------------------------------- 1 | [1.8011670033376514H-308] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_number_with_leading_zero.json: -------------------------------------------------------------------------------- 1 | [012] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_bad_value.json: -------------------------------------------------------------------------------- 1 | ["x", truth] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_bracket_key.json: -------------------------------------------------------------------------------- 1 | {[: "x"} 2 | -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_comma_instead_of_colon.json: -------------------------------------------------------------------------------- 1 | {"x", null} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_double_colon.json: -------------------------------------------------------------------------------- 1 | {"x"::"b"} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_emoji.json: -------------------------------------------------------------------------------- 1 | {🇨🇭} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_garbage_at_end.json: -------------------------------------------------------------------------------- 1 | {"a":"a" 123} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_key_with_single_quotes.json: -------------------------------------------------------------------------------- 1 | {key: 'value'} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_lone_continuation_byte_in_key_and_trailing_comma.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_parsing/n_object_lone_continuation_byte_in_key_and_trailing_comma.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_missing_colon.json: -------------------------------------------------------------------------------- 1 | {"a" b} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_missing_key.json: -------------------------------------------------------------------------------- 1 | {:"b"} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_missing_semicolon.json: -------------------------------------------------------------------------------- 1 | {"a" "b"} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_missing_value.json: -------------------------------------------------------------------------------- 1 | {"a": -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_no-colon.json: -------------------------------------------------------------------------------- 1 | {"a" -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_non_string_key.json: -------------------------------------------------------------------------------- 1 | {1:1} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_non_string_key_but_huge_number_instead.json: -------------------------------------------------------------------------------- 1 | {9999E9999:1} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_repeated_null_null.json: -------------------------------------------------------------------------------- 1 | {null:null,null:null} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_several_trailing_commas.json: -------------------------------------------------------------------------------- 1 | {"id":0,,,,,} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_single_quote.json: -------------------------------------------------------------------------------- 1 | {'a':0} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_trailing_comma.json: -------------------------------------------------------------------------------- 1 | {"id":0,} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_trailing_comment.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}/**/ -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_trailing_comment_open.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}/**// -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_trailing_comment_slash_open.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}// -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_trailing_comment_slash_open_incomplete.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}/ -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_two_commas_in_a_row.json: -------------------------------------------------------------------------------- 1 | {"a":"b",,"c":"d"} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_unquoted_key.json: -------------------------------------------------------------------------------- 1 | {a: "b"} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_unterminated-value.json: -------------------------------------------------------------------------------- 1 | {"a":"a -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_with_single_string.json: -------------------------------------------------------------------------------- 1 | { "foo" : "bar", "a" } -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_object_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}# -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_single_space.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_1_surrogate_then_escape.json: -------------------------------------------------------------------------------- 1 | ["\uD800\"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_1_surrogate_then_escape_u.json: -------------------------------------------------------------------------------- 1 | ["\uD800\u"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_1_surrogate_then_escape_u1.json: -------------------------------------------------------------------------------- 1 | ["\uD800\u1"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_1_surrogate_then_escape_u1x.json: -------------------------------------------------------------------------------- 1 | ["\uD800\u1x"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_accentuated_char_no_quotes.json: -------------------------------------------------------------------------------- 1 | [é] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_backslash_00.json: -------------------------------------------------------------------------------- 1 | ["\"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_escape_x.json: -------------------------------------------------------------------------------- 1 | ["\x00"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_escaped_backslash_bad.json: -------------------------------------------------------------------------------- 1 | ["\\\"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_escaped_ctrl_char_tab.json: -------------------------------------------------------------------------------- 1 | ["\ "] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_escaped_emoji.json: -------------------------------------------------------------------------------- 1 | ["\🌀"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_incomplete_escape.json: -------------------------------------------------------------------------------- 1 | ["\"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_incomplete_escaped_character.json: -------------------------------------------------------------------------------- 1 | ["\u00A"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_incomplete_surrogate.json: -------------------------------------------------------------------------------- 1 | ["\uD834\uDd"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_incomplete_surrogate_escape_invalid.json: -------------------------------------------------------------------------------- 1 | ["\uD800\uD800\x"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_invalid-utf-8-in-escape.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_parsing/n_string_invalid-utf-8-in-escape.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_invalid_backslash_esc.json: -------------------------------------------------------------------------------- 1 | ["\a"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_invalid_unicode_escape.json: -------------------------------------------------------------------------------- 1 | ["\uqqqq"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_invalid_utf8_after_escape.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_parsing/n_string_invalid_utf8_after_escape.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_leading_uescaped_thinspace.json: -------------------------------------------------------------------------------- 1 | [\u0020"asd"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_no_quotes_with_bad_escape.json: -------------------------------------------------------------------------------- 1 | [\n] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_single_doublequote.json: -------------------------------------------------------------------------------- 1 | " -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_single_quote.json: -------------------------------------------------------------------------------- 1 | ['single quote'] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_single_string_no_double_quotes.json: -------------------------------------------------------------------------------- 1 | abc -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_start_escape_unclosed.json: -------------------------------------------------------------------------------- 1 | ["\ -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_unescaped_crtl_char.json: -------------------------------------------------------------------------------- 1 | ["aa"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_unescaped_newline.json: -------------------------------------------------------------------------------- 1 | ["new 2 | line"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_unescaped_tab.json: -------------------------------------------------------------------------------- 1 | [" "] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_unicode_CapitalU.json: -------------------------------------------------------------------------------- 1 | "\UA66D" -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_string_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | ""x -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_U+2060_word_joined.json: -------------------------------------------------------------------------------- 1 | [⁠] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_UTF8_BOM_no_data.json: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_angle_bracket_..json: -------------------------------------------------------------------------------- 1 | <.> -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_angle_bracket_null.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_array_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | [1]x -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_array_with_extra_array_close.json: -------------------------------------------------------------------------------- 1 | [1]] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_array_with_unclosed_string.json: -------------------------------------------------------------------------------- 1 | ["asd] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_ascii-unicode-identifier.json: -------------------------------------------------------------------------------- 1 | aå -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_capitalized_True.json: -------------------------------------------------------------------------------- 1 | [True] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_close_unopened_array.json: -------------------------------------------------------------------------------- 1 | 1] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_comma_instead_of_closing_brace.json: -------------------------------------------------------------------------------- 1 | {"x": true, -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_double_array.json: -------------------------------------------------------------------------------- 1 | [][] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_end_array.json: -------------------------------------------------------------------------------- 1 | ] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_incomplete_UTF8_BOM.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_parsing/n_structure_incomplete_UTF8_BOM.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_lone-invalid-utf-8.json: -------------------------------------------------------------------------------- 1 | � -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_lone-open-bracket.json: -------------------------------------------------------------------------------- 1 | [ -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_no_data.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_parsing/n_structure_no_data.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_null-byte-outside-string.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_number_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | 2@ -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_object_followed_by_closing_object.json: -------------------------------------------------------------------------------- 1 | {}} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_object_unclosed_no_value.json: -------------------------------------------------------------------------------- 1 | {"": -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_object_with_comment.json: -------------------------------------------------------------------------------- 1 | {"a":/*comment*/"b"} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_object_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | {"a": true} "x" -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_open_array_apostrophe.json: -------------------------------------------------------------------------------- 1 | [' -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_open_array_comma.json: -------------------------------------------------------------------------------- 1 | [, -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_open_array_open_object.json: -------------------------------------------------------------------------------- 1 | [{ -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_open_array_open_string.json: -------------------------------------------------------------------------------- 1 | ["a -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_open_array_string.json: -------------------------------------------------------------------------------- 1 | ["a" -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_open_object.json: -------------------------------------------------------------------------------- 1 | { -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_open_object_close_array.json: -------------------------------------------------------------------------------- 1 | {] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_open_object_comma.json: -------------------------------------------------------------------------------- 1 | {, -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_open_object_open_array.json: -------------------------------------------------------------------------------- 1 | {[ -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_open_object_open_string.json: -------------------------------------------------------------------------------- 1 | {"a -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_open_object_string_with_apostrophes.json: -------------------------------------------------------------------------------- 1 | {'a' -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_open_open.json: -------------------------------------------------------------------------------- 1 | ["\{["\{["\{["\{ -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_single_eacute.json: -------------------------------------------------------------------------------- 1 | � -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_single_star.json: -------------------------------------------------------------------------------- 1 | * -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_trailing_#.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}#{} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_uescaped_LF_before_string.json: -------------------------------------------------------------------------------- 1 | [\u000A""] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_unclosed_array.json: -------------------------------------------------------------------------------- 1 | [1 -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_unclosed_array_partial_null.json: -------------------------------------------------------------------------------- 1 | [ false, nul -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_unclosed_array_unfinished_false.json: -------------------------------------------------------------------------------- 1 | [ true, fals -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_unclosed_array_unfinished_true.json: -------------------------------------------------------------------------------- 1 | [ false, tru -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_unclosed_object.json: -------------------------------------------------------------------------------- 1 | {"asd":"asd" -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_unicode-identifier.json: -------------------------------------------------------------------------------- 1 | å -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_whitespace_U+2060_word_joiner.json: -------------------------------------------------------------------------------- 1 | [⁠] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/n_structure_whitespace_formfeed.json: -------------------------------------------------------------------------------- 1 | [ ] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_array_arraysWithSpaces.json: -------------------------------------------------------------------------------- 1 | [[] ] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_array_empty-string.json: -------------------------------------------------------------------------------- 1 | [""] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_array_empty.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_array_ending_with_newline.json: -------------------------------------------------------------------------------- 1 | ["a"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_array_false.json: -------------------------------------------------------------------------------- 1 | [false] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_array_heterogeneous.json: -------------------------------------------------------------------------------- 1 | [null, 1, "1", {}] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_array_null.json: -------------------------------------------------------------------------------- 1 | [null] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_array_with_1_and_newline.json: -------------------------------------------------------------------------------- 1 | [1 2 | ] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_array_with_leading_space.json: -------------------------------------------------------------------------------- 1 | [1] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_array_with_several_null.json: -------------------------------------------------------------------------------- 1 | [1,null,null,null,2] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_array_with_trailing_space.json: -------------------------------------------------------------------------------- 1 | [2] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_number.json: -------------------------------------------------------------------------------- 1 | [123e65] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_number_0e+1.json: -------------------------------------------------------------------------------- 1 | [0e+1] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_number_0e1.json: -------------------------------------------------------------------------------- 1 | [0e1] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_number_after_space.json: -------------------------------------------------------------------------------- 1 | [ 4] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_number_double_close_to_zero.json: -------------------------------------------------------------------------------- 1 | [-0.000000000000000000000000000000000000000000000000000000000000000000000000000001] 2 | -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_number_int_with_exp.json: -------------------------------------------------------------------------------- 1 | [20e1] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_number_minus_zero.json: -------------------------------------------------------------------------------- 1 | [-0] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_number_negative_int.json: -------------------------------------------------------------------------------- 1 | [-123] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_number_negative_one.json: -------------------------------------------------------------------------------- 1 | [-1] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_number_negative_zero.json: -------------------------------------------------------------------------------- 1 | [-0] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_number_real_capital_e.json: -------------------------------------------------------------------------------- 1 | [1E22] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_number_real_capital_e_neg_exp.json: -------------------------------------------------------------------------------- 1 | [1E-2] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_number_real_capital_e_pos_exp.json: -------------------------------------------------------------------------------- 1 | [1E+2] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_number_real_exponent.json: -------------------------------------------------------------------------------- 1 | [123e45] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_number_real_fraction_exponent.json: -------------------------------------------------------------------------------- 1 | [123.456e78] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_number_real_neg_exp.json: -------------------------------------------------------------------------------- 1 | [1e-2] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_number_real_pos_exponent.json: -------------------------------------------------------------------------------- 1 | [1e+2] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_number_simple_int.json: -------------------------------------------------------------------------------- 1 | [123] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_number_simple_real.json: -------------------------------------------------------------------------------- 1 | [123.456789] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_object.json: -------------------------------------------------------------------------------- 1 | {"asd":"sdf", "dfg":"fgh"} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_object_basic.json: -------------------------------------------------------------------------------- 1 | {"asd":"sdf"} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_object_duplicated_key.json: -------------------------------------------------------------------------------- 1 | {"a":"b","a":"c"} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_object_duplicated_key_and_value.json: -------------------------------------------------------------------------------- 1 | {"a":"b","a":"b"} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_object_empty.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_object_empty_key.json: -------------------------------------------------------------------------------- 1 | {"":0} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_object_escaped_null_in_key.json: -------------------------------------------------------------------------------- 1 | {"foo\u0000bar": 42} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_object_extreme_numbers.json: -------------------------------------------------------------------------------- 1 | { "min": -1.0e+28, "max": 1.0e+28 } -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_object_long_strings.json: -------------------------------------------------------------------------------- 1 | {"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_object_simple.json: -------------------------------------------------------------------------------- 1 | {"a":[]} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_object_string_unicode.json: -------------------------------------------------------------------------------- 1 | {"title":"\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430" } -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_object_with_newlines.json: -------------------------------------------------------------------------------- 1 | { 2 | "a": "b" 3 | } -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_1_2_3_bytes_UTF-8_sequences.json: -------------------------------------------------------------------------------- 1 | ["\u0060\u012a\u12AB"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_accepted_surrogate_pair.json: -------------------------------------------------------------------------------- 1 | ["\uD801\udc37"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_accepted_surrogate_pairs.json: -------------------------------------------------------------------------------- 1 | ["\ud83d\ude39\ud83d\udc8d"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_allowed_escapes.json: -------------------------------------------------------------------------------- 1 | ["\"\\\/\b\f\n\r\t"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_backslash_and_u_escaped_zero.json: -------------------------------------------------------------------------------- 1 | ["\\u0000"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_backslash_doublequotes.json: -------------------------------------------------------------------------------- 1 | ["\""] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_comments.json: -------------------------------------------------------------------------------- 1 | ["a/*b*/c/*d//e"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_double_escape_a.json: -------------------------------------------------------------------------------- 1 | ["\\a"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_double_escape_n.json: -------------------------------------------------------------------------------- 1 | ["\\n"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_escaped_control_character.json: -------------------------------------------------------------------------------- 1 | ["\u0012"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_escaped_noncharacter.json: -------------------------------------------------------------------------------- 1 | ["\uFFFF"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_in_array.json: -------------------------------------------------------------------------------- 1 | ["asd"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_in_array_with_leading_space.json: -------------------------------------------------------------------------------- 1 | [ "asd"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_last_surrogates_1_and_2.json: -------------------------------------------------------------------------------- 1 | ["\uDBFF\uDFFF"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_nbsp_uescaped.json: -------------------------------------------------------------------------------- 1 | ["new\u00A0line"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_nonCharacterInUTF-8_U+10FFFF.json: -------------------------------------------------------------------------------- 1 | ["􏿿"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_nonCharacterInUTF-8_U+FFFF.json: -------------------------------------------------------------------------------- 1 | ["￿"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_null_escape.json: -------------------------------------------------------------------------------- 1 | ["\u0000"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_one-byte-utf-8.json: -------------------------------------------------------------------------------- 1 | ["\u002c"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_pi.json: -------------------------------------------------------------------------------- 1 | ["π"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_reservedCharacterInUTF-8_U+1BFFF.json: -------------------------------------------------------------------------------- 1 | ["𛿿"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_simple_ascii.json: -------------------------------------------------------------------------------- 1 | ["asd "] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_space.json: -------------------------------------------------------------------------------- 1 | " " -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json: -------------------------------------------------------------------------------- 1 | ["\uD834\uDd1e"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_three-byte-utf-8.json: -------------------------------------------------------------------------------- 1 | ["\u0821"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_two-byte-utf-8.json: -------------------------------------------------------------------------------- 1 | ["\u0123"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_u+2028_line_sep.json: -------------------------------------------------------------------------------- 1 | ["
"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_u+2029_par_sep.json: -------------------------------------------------------------------------------- 1 | ["
"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_uEscape.json: -------------------------------------------------------------------------------- 1 | ["\u0061\u30af\u30EA\u30b9"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_uescaped_newline.json: -------------------------------------------------------------------------------- 1 | ["new\u000Aline"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_unescaped_char_delete.json: -------------------------------------------------------------------------------- 1 | [""] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_unicode.json: -------------------------------------------------------------------------------- 1 | ["\uA66D"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_unicodeEscapedBackslash.json: -------------------------------------------------------------------------------- 1 | ["\u005C"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_unicode_2.json: -------------------------------------------------------------------------------- 1 | ["⍂㈴⍂"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_unicode_U+10FFFE_nonchar.json: -------------------------------------------------------------------------------- 1 | ["\uDBFF\uDFFE"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_unicode_U+1FFFE_nonchar.json: -------------------------------------------------------------------------------- 1 | ["\uD83F\uDFFE"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json: -------------------------------------------------------------------------------- 1 | ["\u200B"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_unicode_U+2064_invisible_plus.json: -------------------------------------------------------------------------------- 1 | ["\u2064"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_unicode_U+FDD0_nonchar.json: -------------------------------------------------------------------------------- 1 | ["\uFDD0"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_unicode_U+FFFE_nonchar.json: -------------------------------------------------------------------------------- 1 | ["\uFFFE"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_unicode_escaped_double_quote.json: -------------------------------------------------------------------------------- 1 | ["\u0022"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_utf8.json: -------------------------------------------------------------------------------- 1 | ["€𝄞"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_string_with_del_character.json: -------------------------------------------------------------------------------- 1 | ["aa"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_structure_lonely_false.json: -------------------------------------------------------------------------------- 1 | false -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_structure_lonely_int.json: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_structure_lonely_negative_real.json: -------------------------------------------------------------------------------- 1 | -0.1 -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_structure_lonely_null.json: -------------------------------------------------------------------------------- 1 | null -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_structure_lonely_string.json: -------------------------------------------------------------------------------- 1 | "asd" -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_structure_lonely_true.json: -------------------------------------------------------------------------------- 1 | true -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_structure_string_empty.json: -------------------------------------------------------------------------------- 1 | "" -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_structure_trailing_newline.json: -------------------------------------------------------------------------------- 1 | ["a"] 2 | -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_structure_true_in_array.json: -------------------------------------------------------------------------------- 1 | [true] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_parsing/y_structure_whitespace_array.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_transform/number_-9223372036854775808.json: -------------------------------------------------------------------------------- 1 | [-9223372036854775808] 2 | -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_transform/number_-9223372036854775809.json: -------------------------------------------------------------------------------- 1 | [-9223372036854775809] 2 | -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_transform/number_1.0.json: -------------------------------------------------------------------------------- 1 | [1.0] 2 | -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_transform/number_1.000000000000000005.json: -------------------------------------------------------------------------------- 1 | [1.000000000000000005] 2 | -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_transform/number_1000000000000000.json: -------------------------------------------------------------------------------- 1 | [1000000000000000] 2 | -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_transform/number_10000000000000000999.json: -------------------------------------------------------------------------------- 1 | [10000000000000000999] 2 | -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_transform/number_1e-999.json: -------------------------------------------------------------------------------- 1 | [1E-999] 2 | -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_transform/number_1e6.json: -------------------------------------------------------------------------------- 1 | [1E6] 2 | -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_transform/number_9223372036854775807.json: -------------------------------------------------------------------------------- 1 | [9223372036854775807] 2 | -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_transform/number_9223372036854775808.json: -------------------------------------------------------------------------------- 1 | [9223372036854775808] 2 | -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_transform/object_key_nfc_nfd.json: -------------------------------------------------------------------------------- 1 | {"é":"NFC","é":"NFD"} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_transform/object_key_nfd_nfc.json: -------------------------------------------------------------------------------- 1 | {"é":"NFD","é":"NFC"} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_transform/object_same_key_different_values.json: -------------------------------------------------------------------------------- 1 | {"a":1,"a":2} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_transform/object_same_key_same_value.json: -------------------------------------------------------------------------------- 1 | {"a":1,"a":1} -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_transform/object_same_key_unclear_values.json: -------------------------------------------------------------------------------- 1 | {"a":0,"a":-0} 2 | -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_transform/string_1_escaped_invalid_codepoint.json: -------------------------------------------------------------------------------- 1 | ["\uD800"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_transform/string_1_invalid_codepoint.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_transform/string_1_invalid_codepoint.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_transform/string_2_escaped_invalid_codepoints.json: -------------------------------------------------------------------------------- 1 | ["\uD800\uD800"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_transform/string_2_invalid_codepoints.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_transform/string_2_invalid_codepoints.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_transform/string_3_escaped_invalid_codepoints.json: -------------------------------------------------------------------------------- 1 | ["\uD800\uD800\uD800"] -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_transform/string_3_invalid_codepoints.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnmfarrell/jp/08fc2cd70942b8f816b967b43ca01cb986fade24/tests/share/JSONTestSuite/test_transform/string_3_invalid_codepoints.json -------------------------------------------------------------------------------- /tests/share/JSONTestSuite/test_transform/string_with_escaped_NULL.json: -------------------------------------------------------------------------------- 1 | ["A\u0000B"] -------------------------------------------------------------------------------- /tests/share/arrays.jsonp: -------------------------------------------------------------------------------- 1 | [1,true,null,"foo",{"foo":2.3},[1,2,3]] 2 | [2,false,null,"bar",{"bar":-1},[4,5,6]] 3 | -------------------------------------------------------------------------------- /tests/share/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jp", 3 | "version": "0.0.1", 4 | "description": "A JSON processor written in Bash", 5 | "homepage": "http://github.com/dnmfarrell/jp", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/dnmfarrell/jp.git" 9 | }, 10 | "bin": { 11 | "jp": "./jp" 12 | }, 13 | "dependencies": {}, 14 | "devDependencies": {}, 15 | "author": "David Farrell" 16 | } 17 | -------------------------------------------------------------------------------- /tests/transform/and.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | $(./jp -m macros.jp .and 2>/dev/null) 6 | if [ $? -ne 0 ];then 7 | pass "and empty stack errors" 8 | else 9 | fail "and empty stack does not error" 10 | fi 11 | 12 | $(./jp -m macros.jp true .and 2>/dev/null) 13 | if [ $? -ne 0 ];then 14 | pass "and missing right operand errors" 15 | else 16 | fail "and missing right operand does not error" 17 | fi 18 | 19 | $(./jp -m macros.jp null .and 2>/dev/null) 20 | if [ $? -ne 0 ];then 21 | pass "and illegal left operand errors" 22 | else 23 | fail "and illegal left operand does not error" 24 | fi 25 | 26 | $(./jp -m macros.jp false null .and 2>/dev/null) 27 | if [ $? -ne 0 ];then 28 | pass "and illegal right operand errors" 29 | else 30 | fail "and illegal right operand does not error" 31 | fi 32 | 33 | tt=$(./jp -m macros.jp true true .and) 34 | if [ "$tt" = 'true' ];then 35 | pass "and true true returns true" 36 | else 37 | printf -v ttesc "%q" "$tt" 38 | fail "and true true returns: $ttesc" 39 | fi 40 | 41 | tf=$(./jp -m macros.jp true false .and) 42 | if [ "$tf" = 'false' ];then 43 | pass "and true false returns false" 44 | else 45 | printf -v tfesc "%q" "$tf" 46 | fail "and true false returns: $tfesc" 47 | fi 48 | 49 | ft=$(./jp -m macros.jp false true .and) 50 | if [ "$ft" = 'false' ];then 51 | pass "and false true returns false" 52 | else 53 | printf -v ftesc "%q" "$ft" 54 | fail "and false true returns: $ftesc" 55 | fi 56 | 57 | ff=$(./jp -m macros.jp false false .and) 58 | if [ "$ff" = 'false' ];then 59 | pass "and false false returns false" 60 | else 61 | printf -v ffesc "%q" "$ff" 62 | fail "and false false returns: $ffesc" 63 | fi 64 | 65 | end 66 | -------------------------------------------------------------------------------- /tests/transform/collect.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | empty=$(./jp .collect) 6 | if [ "$empty" = '[]' ];then 7 | pass "collect empty stack returns []" 8 | else 9 | printf -v emptyesc "%q" "$empty" 10 | fail "collect empty stack returns: $emptyesc" 11 | fi 12 | 13 | one=$(./jp '" foo bar "' .collect) 14 | if [ "$one" = '[" foo bar "]' ];then 15 | pass 'collect one stack returns ["f"]' 16 | else 17 | printf -v oneesc "%q" "$one" 18 | fail "collect one stack returns: $oneesc" 19 | fi 20 | 21 | five=$(./jp 'false' null 1.5 '{"a b ":[1,23]}' '[]' .collect) 22 | if [ "$five" = '[[],{"a b ":[1,23]},1.5,null,false]' ];then 23 | pass 'collect five stack returns expected' 24 | else 25 | printf -v fiveesc "%q" "$five" 26 | fail "collect five stack returns: $fiveesc" 27 | fi 28 | 29 | end 30 | -------------------------------------------------------------------------------- /tests/transform/concat.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | $(./jp null .concat 2>/dev/null) 6 | if [ $? -ne 0 ];then 7 | pass "concat invalid type errors" 8 | else 9 | fail "concat invalid type does not error" 10 | fi 11 | 12 | $(./jp '{}' '[]' .concat 2>/dev/null) 13 | if [ $? -ne 0 ];then 14 | pass "concat incompatible collection types errors" 15 | else 16 | fail "concat incompatible collection types does not error" 17 | fi 18 | 19 | $(./jp '{}' '"f"' .concat 2>/dev/null) 20 | if [ $? -ne 0 ];then 21 | pass "concat incompatible string types errors" 22 | else 23 | fail "concat incompatible string types does not error" 24 | fi 25 | 26 | $(./jp '"f"' .concat 2>/dev/null) 27 | if [ $? -ne 0 ];then 28 | pass "concat one string errors" 29 | else 30 | fail "concat one string does not error" 31 | fi 32 | 33 | $(./jp [1] .concat 2>/dev/null) 34 | if [ $? -ne 0 ];then 35 | pass "concat one array errors" 36 | else 37 | fail "concat one array does not error" 38 | fi 39 | 40 | $(./jp '{"a":1}' .concat 2>/dev/null) 41 | if [ $? -ne 0 ];then 42 | pass "concat one object errors" 43 | else 44 | fail "concat one object does not error" 45 | fi 46 | 47 | $(./jp '"f"' .concat 2>/dev/null) 48 | if [ $? -ne 0 ];then 49 | pass "concat one string errors" 50 | else 51 | fail "concat one string does not error" 52 | fi 53 | 54 | str=$(echo '"f "' | ./jp '"bar"' .concat) 55 | if [ "$str" = '"barf "' ];then 56 | pass 'concat str string returns "barf "' 57 | else 58 | printf -v stresc "%q" "$str" 59 | fail "concat str string returns unexpected: $stresc" 60 | fi 61 | 62 | emptyarr=$(./jp [] [] .concat) 63 | if [ "$emptyarr" = '[]' ];then 64 | pass 'concat empty arrays returns []' 65 | else 66 | printf -v emptyarresc "%q" "$emptyarr" 67 | fail "concat empty arrays returns unexpected: $emptyarresc" 68 | fi 69 | 70 | emptyarr=$(./jp '[]' '["foo"]' .concat) 71 | if [ "$emptyarr" = '["foo"]' ];then 72 | pass 'concat one array with empty returns ["foo"]' 73 | else 74 | printf -v emptyesc "%q" "$emptyarr" 75 | fail "concat one array with empty return: $emptyesc" 76 | fi 77 | 78 | arr=$(./jp '[{"a":1}]' '["foo"]' .concat) 79 | if [ "$arr" = '["foo",{"a":1}]' ];then 80 | pass 'concat arrays return ["foo",{"a":1},1]' 81 | else 82 | printf -v arresc "%q" "$arr" 83 | fail "concat arrays return unexpected: $arresc" 84 | fi 85 | 86 | emptyobj=$(./jp '{}' '{}' .concat) 87 | if [ "$emptyobj" = '{}' ];then 88 | pass 'concat empty objects returns {}' 89 | else 90 | printf -v emptyobjesc "%q" "$emptyobj" 91 | fail "concat empty objects returns unexpected: $emptyobjesc" 92 | fi 93 | 94 | oneobj=$(./jp '{"A":1}' {} .concat) 95 | if [ "$oneobj" = '{"A":1}' ];then 96 | pass 'concat one object with empty returns {"A":1}' 97 | else 98 | printf -v oneobjesc "%q" "$oneobj" 99 | fail "concat one object with empty returns unexpected: $oneobjesc" 100 | fi 101 | 102 | obj=$(./jp '{"a":[1]}' '{"foo":5}' .concat) 103 | if [ "$obj" = '{"foo":5,"a":[1]}' ];then 104 | pass 'concat objects return {"foo":5,"a":[1]}' 105 | else 106 | printf -v objesc "%q" "$obj" 107 | fail "concat objects return unexpected: $objesc" 108 | fi 109 | 110 | end 111 | -------------------------------------------------------------------------------- /tests/transform/cons.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | $(./jp .cons 2>/dev/null) 6 | if [ $? -ne 0 ];then 7 | pass "cons without args errors" 8 | else 9 | fail "cons without args does not error" 10 | fi 11 | 12 | $(./jp 1 .cons 2>/dev/null) 13 | if [ $? -ne 0 ];then 14 | pass "cons one arg errors" 15 | else 16 | fail "cons one arg does not error" 17 | fi 18 | 19 | $(./jp 1 2 .cons 2>/dev/null) 20 | if [ $? -ne 0 ];then 21 | pass "cons no array errors" 22 | else 23 | fail "cons no array does not error" 24 | fi 25 | 26 | empty=$(./jp [] [] .cons) 27 | if [ "$empty" = $'[[]]' ];then 28 | pass "cons two empty arrays" 29 | else 30 | printf -v emptyesc "%q" "$empty" 31 | fail "cons two empty arrays returns: $emptyesc" 32 | fi 33 | 34 | one=$(./jp [] 1 .cons) 35 | if [ "$one" = $'[1]' ];then 36 | pass "cons into empty array returns [1]" 37 | else 38 | printf -v oneesc "%q" "$one" 39 | fail "cons into empty array returns: $oneesc" 40 | fi 41 | 42 | two=$(./jp [2] 1 .cons) 43 | if [ "$two" = $'[1,2]' ];then 44 | pass "cons into an array returns [1,2]" 45 | else 46 | printf -v twoesc "%q" "$two" 47 | fail "cons into an array returns: $twoesc" 48 | fi 49 | 50 | end 51 | -------------------------------------------------------------------------------- /tests/transform/do.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | $(./jp .do 2>/dev/null) 6 | if [ $? -ne 0 ];then 7 | pass "unterminated do errors" 8 | else 9 | fail "unterminated do does not error" 10 | fi 11 | 12 | $(./jp .done 2>/dev/null) 13 | if [ $? -ne 0 ];then 14 | pass "naked done errors" 15 | else 16 | fail "naked done does not error" 17 | fi 18 | 19 | $(./jp .do .do .done 2>/dev/null) 20 | if [ $? -ne 0 ];then 21 | pass "unterminated nested do errors" 22 | else 23 | fail "unterminated nested do does not error" 24 | fi 25 | 26 | vals=$(./jp .do 1 2 3 .done) 27 | if [ "$vals" = $'3\n2\n1' ];then 28 | pass "do block pushes two vals on the stack" 29 | else 30 | printf -v valsesc "%q" "$vals" 31 | fail "do block pushes two vals on the stack but returns: $valsesc" 32 | fi 33 | 34 | seq=$(./jp .do 1 .done .do 2 .done .do 3 .done) 35 | if [ "$seq" = $'3\n2\n1' ];then 36 | pass "sequential do blocks push values on stack" 37 | else 38 | printf -v seqesc "%q" "$seq" 39 | fail "sequential do blocks return: $seqesc" 40 | fi 41 | 42 | nest=$(./jp .do 1 .do 2 .do 3 .done .done .done) 43 | if [ "$nest" = $'3\n2\n1' ];then 44 | pass "nested do blocks push values on stack" 45 | else 46 | printf -v nestesc "%q" "$nest" 47 | fail "nested do blocks return: $nestesc" 48 | fi 49 | 50 | end 51 | -------------------------------------------------------------------------------- /tests/transform/dup.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | empty=$(./jp .dup 2>/dev/null) 6 | if [ $? -ne 0 ];then 7 | pass "dup empty stack errors" 8 | else 9 | fail "dup empty stack does not error" 10 | fi 11 | 12 | once=$(./jp [1] .dup) 13 | if [ "$once" = $'[1]\n[1]' ];then 14 | pass "dup once" 15 | else 16 | printf -v onceesc "%q" "$once" 17 | fail "dup once: got $onceesc" 18 | fi 19 | 20 | twice=$(./jp '[" a\tb c "]' .dup .dup) 21 | if [ "$twice" = $'[" a\\tb c "]\n[" a\\tb c "]\n[" a\\tb c "]' ];then 22 | pass "dup twice" 23 | else 24 | printf -v twiceesc "%q" "$twice" 25 | fail "dup twice: got $twiceesc" 26 | fi 27 | 28 | two=$(./jp 'true' 'false' .dup) 29 | if [ "$two" = $'false\nfalse\ntrue' ];then 30 | pass "dup two stack" 31 | else 32 | printf -v twoesc "%q" "$two" 33 | fail "dup two stack: got $twoesc" 34 | fi 35 | 36 | end 37 | -------------------------------------------------------------------------------- /tests/transform/exists.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | $(./jp -m macros.jp .exists 2>/dev/null) 6 | if [ $? -ne 0 ];then 7 | pass "exists on empty stack errors" 8 | else 9 | fail "exists on empty stack does not error" 10 | fi 11 | 12 | $(./jp -m macros.jp {} 1 .exists 2>/dev/null) 13 | if [ $? -ne 0 ];then 14 | pass "exists on non-string stack errors" 15 | else 16 | fail "exists on non-string stack does not error" 17 | fi 18 | 19 | $(./jp -m macros.jp 1 '"f"' .exists 2>/dev/null) 20 | if [ $? -ne 0 ];then 21 | pass "exists on non-object stack errors" 22 | else 23 | fail "exists on non-object stack does not error" 24 | fi 25 | 26 | empty=$(./jp -m macros.jp '{}' '"foo"' .exists) 27 | if [ "$empty" = $'false' ];then 28 | pass "exists on empty object returns false" 29 | else 30 | printf -v emptyesc "%q" "$empty" 31 | fail "exists on empty object doesn't return false: $emptyesc" 32 | fi 33 | 34 | first=$(./jp -m macros.jp '{"a":1,"b":2}' '"a"' .exists) 35 | if [ "$first" = $'true' ];then 36 | pass "exists matches first key in object" 37 | else 38 | printf -v firstesc "%q" "$first" 39 | fail "exists doesn't match first key in object: $firstesc" 40 | fi 41 | 42 | last=$(./jp -m macros.jp '{"a":1,"b":2}' '"b"' .exists) 43 | if [ "$last" = $'true' ];then 44 | pass "exists matches last key in object" 45 | else 46 | printf -v lastesc "%q" "$last" 47 | fail "exists doesn't match last key in object: $lastesc" 48 | fi 49 | 50 | zero=$(./jp -m macros.jp '{"":1}' '""' .exists) 51 | if [ "$zero" = $'true' ];then 52 | pass "exists matches empty string" 53 | else 54 | printf -v zeroesc "%q" "$zero" 55 | fail "exists doesn't match empty string: $zeroesc" 56 | fi 57 | 58 | end 59 | -------------------------------------------------------------------------------- /tests/transform/h.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | $(./jp .h 2>/dev/null) 6 | if [ $? -ne 0 ];then 7 | pass "h on empty stack errors" 8 | else 9 | fail "h on empty stack does not error" 10 | fi 11 | 12 | $(./jp {} .h 2>/dev/null) 13 | if [ $? -ne 0 ];then 14 | pass "h on non-array errors" 15 | else 16 | fail "h on non-array does not error" 17 | fi 18 | 19 | $(./jp [] .h 2>/dev/null) 20 | if [ $? -ne 0 ];then 21 | pass "h on empty array errors" 22 | else 23 | fail "h on empty array does not error" 24 | fi 25 | 26 | empty=$(./jp '["",2,3]' .h) 27 | if [ "$empty" = '""' ];then 28 | pass $"h on empty string val returns \"\"" 29 | else 30 | printf -v emptyesc "%q" "$empty" 31 | fail "h on empty string val returns: $emptyesc" 32 | fi 33 | 34 | null=$(./jp '[null,2,3]' .h) 35 | if [ "$null" = 'null' ];then 36 | pass $"h on null val returns null" 37 | else 38 | printf -v nullesc "%q" "$null" 39 | fail "h on null val returns: $nullesc" 40 | fi 41 | 42 | abc=$(./jp '[1,2,3]' .h) 43 | if [ "$abc" = '1' ];then 44 | pass 'h [1,2,3] returns 1' 45 | else 46 | printf -v abcesc "%q" "$abc" 47 | fail $"h [1,2,3] returns: $abcesc" 48 | fi 49 | 50 | nest=$(./jp '[[1,[2,[3]]]]' .h) 51 | if [ "$nest" = '[1,[2,[3]]]' ];then 52 | pass 'h [1,[2,[3]]] returns 1' 53 | else 54 | printf -v nestesc "%q" "$nest" 55 | fail $"h [1,[2,[3]]] returns: $nestesc" 56 | fi 57 | 58 | end 59 | -------------------------------------------------------------------------------- /tests/transform/idx.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | $(./jp .idx 2>/dev/null) 6 | if [ $? -ne 0 ];then 7 | pass "idx errors on missing both args" 8 | else 9 | fail "idx errors on missing both args" 10 | fi 11 | $(./jp 1 .idx 2>/dev/null) 12 | if [ $? -ne 0 ];then 13 | pass "idx errors missing 1 arg" 14 | else 15 | fail "idx errors missing 1 arg" 16 | fi 17 | $(./jp [] -1 .idx 2>/dev/null) 18 | if [ $? -ne 0 ];then 19 | pass "idx errors negative index" 20 | else 21 | fail "idx errors negative index" 22 | fi 23 | $(./jp [] true .idx 2>/dev/null) 24 | if [ $? -ne 0 ];then 25 | pass "idx errors wrong 1st arg type" 26 | else 27 | fail "idx errors wrong 1st arg type" 28 | fi 29 | $(./jp {} 0 .idx 2>/dev/null) 30 | if [ $? -ne 0 ];then 31 | pass "idx errors wrong 2nd arg type" 32 | else 33 | fail "idx errors wrong 2nd arg type" 34 | fi 35 | empty=$(./jp [] 0 .idx) 36 | if [ "$empty" = '' ];then 37 | pass "empty array returns nothing" 38 | else 39 | printf -v emptyesc "%q" "$empty" 40 | fail "empty array returns nothing: $emptyesc" 41 | fi 42 | gtr=$(./jp [0] 1 .idx) 43 | if [ "$gtr" = '' ];then 44 | pass "idx greater than array len returns nothing" 45 | else 46 | printf -v gtresc "%q" "$gtr" 47 | fail "idx greater than array len returns nothing $gtresc" 48 | fi 49 | zeroth=$(./jp '["foo","bar","baz"]' 0 .idx) 50 | if [ "$zeroth" = '"foo"' ];then 51 | pass "zeroth element matches \"foo\"" 52 | else 53 | printf -v zerothesc "%q" "$zeroth" 54 | fail "zeroth element matches \"foo\": $zerothesc" 55 | fi 56 | last=$(./jp '["foo","bar","baz"]' 2 .idx) 57 | if [ "$last" = '"baz"' ];then 58 | pass "last element is \"baz\"" 59 | else 60 | printf -v lastesc "%q" "$last" 61 | fail "last element is \"baz\": $lastesc" 62 | fi 63 | nest=$(./jp '["foo",[1,2,3,4,5],"baz"]' 1 .idx) 64 | if [ "$nest" = '[1,2,3,4,5]' ];then 65 | pass "got nested array" 66 | else 67 | printf -v nestesc "%q" "$nest" 68 | fail "got nested array: $nestesc" 69 | fi 70 | 71 | end 72 | -------------------------------------------------------------------------------- /tests/transform/if.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | $(./jp .if 2>/dev/null) 6 | if [ $? -ne 0 ];then 7 | pass "if empty stack errors" 8 | else 9 | fail "if empty stack does not error" 10 | fi 11 | 12 | $(./jp null .if 2>/dev/null) 13 | if [ $? -ne 0 ];then 14 | pass "if illegal operand type errors" 15 | else 16 | fail "if illegal operand type does not error" 17 | fi 18 | 19 | $(./jp .else 2>/dev/null) 20 | if [ $? -ne 0 ];then 21 | pass "naked else errors" 22 | else 23 | fail "naked else does not error" 24 | fi 25 | 26 | t=$(./jp 'true' .if 1) 27 | if [ "$t" = '1' ];then 28 | pass "true if 1 returns 1" 29 | else 30 | printf -v tesc "%q" "$t" 31 | fail "true if 1 returns: $tesc" 32 | fi 33 | 34 | te=$(./jp 'true' .if 1 .else 2) 35 | if [ "$te" = '1' ];then 36 | pass "true if 1 ... else returns 1" 37 | else 38 | printf -v teesc "%q" "$te" 39 | fail "true if 1 ... else returns: $teesc" 40 | fi 41 | 42 | ted=$(./jp 'true' .if .do 1 .done .else .do 2 .done) 43 | if [ "$ted" = '1' ];then 44 | pass "true if .do 1 ... else returns 1" 45 | else 46 | printf -v tedesc "%q" "$ted" 47 | fail "true if 1 .do ... else returns: $tedesc" 48 | fi 49 | 50 | f=$(./jp 'false' .if 1) 51 | if [ "$f" = '' ];then 52 | pass "false if 1 returns empty string" 53 | else 54 | printf -v fesc "%q" "$f" 55 | fail "false if 1 returns: $fesc" 56 | fi 57 | 58 | fe=$(./jp 'false' .if 1 .else 2) 59 | if [ "$fe" = '2' ];then 60 | pass "false if ... else 2 returns 2" 61 | else 62 | printf -v feesc "%q" "$fe" 63 | fail "false if ... else 2 returns: $feesc" 64 | fi 65 | 66 | fed=$(./jp 'false' .if .do 1 .done .else .do 2 .done) 67 | if [ "$fed" = '2' ];then 68 | pass "false if ... else .do 2 .done returns 2" 69 | else 70 | printf -v fedesc "%q" "$fed" 71 | fail "false if ... else .do 2 .done returns: $fedesc" 72 | fi 73 | 74 | end 75 | -------------------------------------------------------------------------------- /tests/transform/json-test-suite.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | 4 | function test_transform { 5 | local filepath="$1" 6 | local expect=$(cat "$filepath") 7 | local result=$(./jp "$expect") 8 | if [ "$result" = "$expect" ];then 9 | pass "$filepath returns expected" 10 | else 11 | printf -v returnesc "%q" "$return" 12 | fail "$filepath returns unexpected result: $returnesc" 13 | fi 14 | } 15 | 16 | for file in tests/share/JSONTestSuite/test_transform/*;do 17 | echo "$file" 18 | test_transform "$file" 19 | done 20 | 21 | end 22 | -------------------------------------------------------------------------------- /tests/transform/k.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | $(./jp .k 2>/dev/null) 6 | if [ $? -ne 0 ];then 7 | pass "k on empty stack errors" 8 | else 9 | fail "k on empty stack does not error" 10 | fi 11 | 12 | $(./jp '"f"' .k 2>/dev/null) 13 | if [ $? -ne 0 ];then 14 | pass "k on non-object errors" 15 | else 16 | fail "k on non-object does not error" 17 | fi 18 | 19 | $(./jp {} .k 2>/dev/null) 20 | if [ $? -ne 0 ];then 21 | pass "k on empty object errors" 22 | else 23 | fail "k on empty object does not error" 24 | fi 25 | 26 | empty=$(./jp '{"":1}' .k) 27 | if [ "$empty" = '""' ];then 28 | pass "k on empty key returns empty string" 29 | else 30 | printf -v emptyesc "%q" "$empty" 31 | fail "k on empty key returns: $emptyesc" 32 | fi 33 | 34 | abc=$(./jp '{"abc":1}' .k) 35 | if [ "$abc" = '"abc"' ];then 36 | pass 'k {"abc":1} returns "abc"' 37 | else 38 | printf -v abcesc "%q" "$abc" 39 | fail $"k {\"abc\":1} returns: $abcesc" 40 | fi 41 | 42 | end 43 | -------------------------------------------------------------------------------- /tests/transform/keyval.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | $(./jp .keyval 2>/dev/null) 6 | if [ $? -ne 0 ];then 7 | pass "keyval errors on missing both args" 8 | else 9 | fail "keyval errors on missing both args" 10 | fi 11 | $(./jp '""' .keyval 2>/dev/null) 12 | if [ $? -ne 0 ];then 13 | pass "keyval errors missing 1 arg" 14 | else 15 | fail "keyval errors missing 1 arg" 16 | fi 17 | $(./jp {} true .keyval 2>/dev/null) 18 | if [ $? -ne 0 ];then 19 | pass "keyval errors wrong 1st arg type" 20 | else 21 | fail "keyval errors wrong 1st arg type" 22 | fi 23 | $(./jp [] '""' .keyval 2>/dev/null) 24 | if [ $? -ne 0 ];then 25 | pass "keyval errors wrong 2nd arg type" 26 | else 27 | fail "keyval errors wrong 2nd arg type" 28 | fi 29 | empty=$(./jp {} '"f"' .keyval) 30 | if [ "$empty" = '' ];then 31 | pass "empty object returns nothing" 32 | else 33 | printf -v emptyesc "%q" "$empty" 34 | fail "empty object returns nothing: $emptyesc" 35 | fi 36 | nomatch=$(./jp '{"f":1}' '"g"' .keyval) 37 | if [ "$nomatch" = '' ];then 38 | pass "keyval unmatched key returns nothing" 39 | else 40 | printf -v nomatchesc "%q" "$nomatch" 41 | fail "keyval unmatched key returns nothing $nomatchesc" 42 | fi 43 | first=$(./jp '{"foo":1,"bar":2,"baz":3}' '"foo"' .keyval) 44 | if [ "$first" = '1' ];then 45 | pass "first element is 1" 46 | else 47 | printf -v firstesc "%q" "$first" 48 | fail "first element is 1: $firstesc" 49 | fi 50 | last=$(./jp '{"foo":1,"bar":2,"baz":3}' '"baz"' .keyval) 51 | if [ "$last" = '3' ];then 52 | pass "last element is 3" 53 | else 54 | printf -v lastesc "%q" "$last" 55 | fail "last element is 3: $lastesc" 56 | fi 57 | nest=$(./jp '{"foo":1,"bar":{"a":2,"b":[1,2,3]},"baz":3}' '"bar"' .keyval) 58 | if [ "$nest" = '{"a":2,"b":[1,2,3]}' ];then 59 | pass "got nested object" 60 | else 61 | printf -v nestesc "%q" "$nest" 62 | fail "got nested object: $nestesc" 63 | fi 64 | 65 | end 66 | -------------------------------------------------------------------------------- /tests/transform/map.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | $(./jp [1,2,3] .map 2>/dev/null) 6 | if [ $? -ne 0 ];then 7 | pass "map without expression errors" 8 | else 9 | fail "map without expression does not error" 10 | fi 11 | 12 | $(./jp [1,2,3] .map [1] .map 2>/dev/null) 13 | if [ $? -ne 0 ];then 14 | pass "seq maps without expression errors" 15 | else 16 | fail "seq maps without expression do not error" 17 | fi 18 | 19 | arrvals=$(./jp [1,2,3] .map .do .done) 20 | if [ "$arrvals" = $'3\n2\n1' ];then 21 | pass "empty map pushes array elements on to stack" 22 | else 23 | printf -v arrvalsesc "%q" "$arrvals" 24 | fail "empty map returns: $arrvalsesc" 25 | fi 26 | 27 | objvals=$(./jp '{"a":1,"b":2}' .map .do .done) 28 | if [ "$objvals" = $'{"b":2}\n{"a":1}' ];then 29 | pass "empty map pushes object pairs on to stack" 30 | else 31 | printf -v objvalsesc "%q" "$objvals" 32 | fail "empty map returns: $objvalsesc" 33 | fi 34 | 35 | seq=$(./jp '{"a":1,"b":2}' .map .do .done .concat .map .v) 36 | if [ "$seq" = $'1\n2' ];then 37 | pass "sequential maps chain stack operations" 38 | else 39 | printf -v seqesc "%q" "$seq" 40 | fail "sequential maps return: $seqesc" 41 | fi 42 | 43 | nest=$(./jp '{"a":1,"b":2}' .map .map .v) 44 | if [ "$nest" = $'2\n1' ];then 45 | pass "nested maps chain stack operations" 46 | else 47 | printf -v nestesc "%q" "$nest" 48 | fail "nested maps return: $nestesc" 49 | fi 50 | 51 | end 52 | -------------------------------------------------------------------------------- /tests/transform/match.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | $(./jp .match 2>/dev/null) 6 | if [ $? -ne 0 ];then 7 | pass "match empty stack errors" 8 | else 9 | fail "match empty stack does not error" 10 | fi 11 | 12 | $(./jp '"*"' .match 2>/dev/null) 13 | if [ $? -ne 0 ];then 14 | pass "match missing right operand errors" 15 | else 16 | fail "match missing right operand does not error" 17 | fi 18 | 19 | $(./jp null .match 2>/dev/null) 20 | if [ $? -ne 0 ];then 21 | pass "match illegal operand type errors" 22 | else 23 | fail "match illegal operand type does not error" 24 | fi 25 | 26 | $(./jp '{}' '"*"' .match 2>/dev/null) 27 | if [ $? -ne 0 ];then 28 | pass "match illegal type errors" 29 | else 30 | fail "match illegal type does not error" 31 | fi 32 | 33 | strmatch=$(./jp '"f"' '"[a-z]"' .match) 34 | if [ "$strmatch" = 'true' ];then 35 | pass "match f [a-z] returns true" 36 | else 37 | printf -v strmatchesc "%q" "$strmatch" 38 | fail "match f [a-z] returns: $strmatchesc" 39 | fi 40 | 41 | strdiff=$(./jp '""' '"[A-Z]"' .match) 42 | if [ "$strdiff" = 'false' ];then 43 | pass "match '' [A-Z] returns false" 44 | else 45 | printf -v strdiffesc "%q" "$strdiff" 46 | fail "match '' [A-Z] returns: $strdiffesc" 47 | fi 48 | 49 | intmatch=$(./jp 17 '"[0-9]+"' .match) 50 | if [ "$intmatch" = 'true' ];then 51 | pass "match 17 [0-9]+ returns true" 52 | else 53 | printf -v intmatchesc "%q" "$intmatch" 54 | fail "match 17 [0-9]+ returns: $intmatchesc" 55 | fi 56 | 57 | intdiff=$(./jp 5 '"[a-z]"' .match) 58 | if [ "$intdiff" = 'false' ];then 59 | pass "match 5 [a-z] returns false" 60 | else 61 | printf -v intdiffesc "%q" "$intdiff" 62 | fail "match 5 [a-z] returns: $intdiffesc" 63 | fi 64 | 65 | end 66 | -------------------------------------------------------------------------------- /tests/transform/not.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | $(./jp -m macros.jp .not 2>/dev/null) 6 | if [ $? -ne 0 ];then 7 | pass "not empty stack errors" 8 | else 9 | fail "not empty stack does not error" 10 | fi 11 | 12 | $(./jp -m macros.jp null .not 2>/dev/null) 13 | if [ $? -ne 0 ];then 14 | pass "not illegal operand type errors" 15 | else 16 | fail "not illegal operand type does not error" 17 | fi 18 | 19 | t=$(./jp -m macros.jp 'true' .not) 20 | if [ "$t" = 'false' ];then 21 | pass "true not returns false" 22 | else 23 | printf -v tesc "%q" "$t" 24 | fail "true not returns: $tesc" 25 | fi 26 | 27 | f=$(./jp -m macros.jp 'false' .not) 28 | if [ "$f" = 'true' ];then 29 | pass "false not returns true" 30 | else 31 | printf -v fesc "%q" "$f" 32 | fail "false not returns: $fesc" 33 | fi 34 | 35 | end 36 | -------------------------------------------------------------------------------- /tests/transform/or.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | $(./jp -m macros.jp .or 2>/dev/null) 6 | if [ $? -ne 0 ];then 7 | pass "or empty stack errors" 8 | else 9 | fail "or empty stack does not error" 10 | fi 11 | 12 | $(./jp -m macros.jp true .or 2>/dev/null) 13 | if [ $? -ne 0 ];then 14 | pass "or missing right operand errors" 15 | else 16 | fail "or missing right operand does not error" 17 | fi 18 | 19 | $(./jp -m macros.jp null .or 2>/dev/null) 20 | if [ $? -ne 0 ];then 21 | pass "or illegal left operand errors" 22 | else 23 | fail "or illegal left operand does not error" 24 | fi 25 | 26 | $(./jp -m macros.jp false null .or 2>/dev/null) 27 | if [ $? -ne 0 ];then 28 | pass "or illegal right operand errors" 29 | else 30 | fail "or illegal right operand does not error" 31 | fi 32 | 33 | tt=$(./jp -m macros.jp true true .or) 34 | if [ "$tt" = 'true' ];then 35 | pass "or true true returns true" 36 | else 37 | printf -v ttesc "%q" "$tt" 38 | fail "or true true returns: $ttesc" 39 | fi 40 | 41 | tf=$(./jp -m macros.jp true false .or) 42 | if [ "$tf" = 'true' ];then 43 | pass "or true false returns true" 44 | else 45 | printf -v tfesc "%q" "$tf" 46 | fail "or true false returns: $tfesc" 47 | fi 48 | 49 | ft=$(./jp -m macros.jp false true .or) 50 | if [ "$ft" = 'true' ];then 51 | pass "or false true returns true" 52 | else 53 | printf -v ftesc "%q" "$ft" 54 | fail "or false true returns: $ftesc" 55 | fi 56 | 57 | ff=$(./jp -m macros.jp false false .or) 58 | if [ "$ff" = 'false' ];then 59 | pass "or false false returns false" 60 | else 61 | printf -v ffesc "%q" "$ff" 62 | fail "or false false returns: $ffesc" 63 | fi 64 | 65 | end 66 | -------------------------------------------------------------------------------- /tests/transform/pop.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | 4 | empty=$(./jp .pop 2>/dev/null) 5 | if [ $? -ne 0 ];then 6 | pass "pop empty stack errors" 7 | else 8 | fail "pop empty stack does not error" 9 | fi 10 | 11 | popone=$(./jp '{"a":1}' .pop) 12 | if [ "$popone" = '' ];then 13 | pass "pop popone" 14 | else 15 | printf -v poponeesc "%q" "$popone" 16 | fail "pop popone: got $poponeesc" 17 | fi 18 | 19 | poptwo=$(./jp 1 '{}' '[]' .pop .pop) 20 | if [ "$poptwo" = '1' ];then 21 | pass "pop poptwo" 22 | else 23 | printf -v poptwoesc "%q" "$poptwo" 24 | fail "pop poptwo: got $poptwoesc" 25 | fi 26 | 27 | end 28 | -------------------------------------------------------------------------------- /tests/transform/push.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | string=$(echo '" He llo "' | ./jp '"World!"' '""') 6 | if [ $string = $'""\n"World!"\n" He llo "' ];then 7 | pass "push string" 8 | else 9 | printf -v stringesc "%q" "$string" 10 | fail "push string: got $stringesc" 11 | fi 12 | 13 | num=$(echo '1' | ./jp 2.0 -50) 14 | if [ "$num" = $'-50\n2.0\n1' ];then 15 | pass "push num" 16 | else 17 | printf -v numesc "%q" "$num" 18 | fail "push num: got $numesc" 19 | fi 20 | 21 | bool=$(echo 'false' | ./jp 'true') 22 | if [ "$bool" = $'true\nfalse' ];then 23 | pass "push bool" 24 | else 25 | printf -v boolesc "%q" "$bool" 26 | fail "push bool: got $boolesc" 27 | fi 28 | 29 | null=$(echo 'null' | ./jp 'null') 30 | if [ "$null" = $'null\nnull' ];then 31 | pass "push null" 32 | else 33 | printf -v nullesc "%q" "$null" 34 | fail "push null: got $nullesc" 35 | fi 36 | 37 | array=$(echo '[1]' | ./jp '[1,2,[3]]' '[]') 38 | if [ "$array" = $'[]\n[1,2,[3]]\n[1]' ];then 39 | pass "push array" 40 | else 41 | printf -v arrayesc "%q" "$array" 42 | fail "push array: got $arrayesc" 43 | fi 44 | 45 | object=$(echo '{"a":1}' | ./jp '{"b":{"c":3}}' '{}') 46 | if [ "$object" = $'{}\n{"b":{"c":3}}\n{"a":1}' ];then 47 | pass "push object" 48 | else 49 | printf -v objectesc "%q" "$object" 50 | fail "push object: got $objectesc" 51 | fi 52 | 53 | end 54 | -------------------------------------------------------------------------------- /tests/transform/swap.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | $(./jp .swap 2>/dev/null) 6 | if [ $? -ne 0 ];then 7 | pass "swap empty stack errors" 8 | else 9 | fail "swap empty stack does not error" 10 | fi 11 | 12 | $(./jp 1 .swap 2>/dev/null) 13 | if [ $? -ne 0 ];then 14 | pass "swap one stack errors" 15 | else 16 | fail "swap one stack does not error" 17 | fi 18 | 19 | twice=$(./jp '[" a c "]' '["b"]' .swap .swap) 20 | if [ "$twice" = $'["b"]\n[" a c "]' ];then 21 | pass "swap twice" 22 | else 23 | printf -v twiceesc "%q" "$twice" 24 | fail "swap twice returns: $twiceesc" 25 | fi 26 | 27 | two=$(echo '["a"]' | ./jp '["b"]' .swap) 28 | if [ "$two" = $'["a"]\n["b"]' ];then 29 | pass "swap two stack" 30 | else 31 | printf -v twoesc "%q" "$two" 32 | fail "swap two stack returns: $twoesc" 33 | fi 34 | 35 | three=$(echo '["c"]' | ./jp '["b"]' '["a"]' .swap) 36 | if [ "$three" = $'["b"]\n["a"]\n["c"]' ];then 37 | pass "swap three stack" 38 | else 39 | printf -v threeesc "%q" "$three" 40 | fail "swap three stack returns: $threeesc" 41 | fi 42 | 43 | end 44 | -------------------------------------------------------------------------------- /tests/transform/t.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | $(./jp .t 2>/dev/null) 6 | if [ $? -ne 0 ];then 7 | pass "t on empty stack errors" 8 | else 9 | fail "t on empty stack does not error" 10 | fi 11 | 12 | $(./jp {} .t 2>/dev/null) 13 | if [ $? -ne 0 ];then 14 | pass "t on non-array errors" 15 | else 16 | fail "t on non-array does not error" 17 | fi 18 | 19 | $(./jp [] .t 2>/dev/null) 20 | if [ $? -ne 0 ];then 21 | pass "t on empty array errors" 22 | else 23 | fail "t on empty array does not error" 24 | fi 25 | 26 | empty=$(./jp '[1]' .t) 27 | if [ "$empty" = '[]' ];then 28 | pass 't [1] returns []' 29 | else 30 | printf -v emptyesc "%q" "$empty" 31 | fail $"t [1] returns: $emptyesc" 32 | fi 33 | 34 | abc=$(./jp '[1,2,3]' .t) 35 | if [ "$abc" = '[2,3]' ];then 36 | pass 't [1,2,3] returns 1' 37 | else 38 | printf -v abcesc "%q" "$abc" 39 | fail $"t [1,2,3] returns: $abcesc" 40 | fi 41 | 42 | nest=$(./jp '[4,[1,[2,[3]]]]' .t) 43 | if [ "$nest" = '[[1,[2,[3]]]]' ];then 44 | pass 't returns nested array' 45 | else 46 | printf -v nestesc "%q" "$nest" 47 | fail $"t on nested array returns: $nestesc" 48 | fi 49 | 50 | end 51 | -------------------------------------------------------------------------------- /tests/transform/test.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | $(./jp .eq 2>/dev/null) 6 | if [ $? -ne 0 ];then 7 | pass "test empty stack errors" 8 | else 9 | fail "test empty stack does not error" 10 | fi 11 | 12 | $(./jp 1 .eq 2>/dev/null) 13 | if [ $? -ne 0 ];then 14 | pass "test missing right operand errors" 15 | else 16 | fail "test missing right operand does not error" 17 | fi 18 | 19 | $(./jp null null .eq 2>/dev/null) 20 | if [ $? -ne 0 ];then 21 | pass "test illegal operand type errors" 22 | else 23 | fail "test illegal operand type does not error" 24 | fi 25 | 26 | $(./jp 1 '"f"' .eq 2>/dev/null) 27 | if [ $? -ne 0 ];then 28 | pass "test mismatched types errors" 29 | else 30 | fail "test mismatched types does not error" 31 | fi 32 | 33 | $(./jp '"f"' 1 .eq 2>/dev/null) 34 | if [ $? -ne 0 ];then 35 | pass "test mismatched types errors" 36 | else 37 | fail "test mismatched types does not error" 38 | fi 39 | 40 | $(./jp '"f"' '"f"' .ge 2>/dev/null) 41 | if [ $? -ne 0 ];then 42 | pass "test invalid string op errors" 43 | else 44 | fail "test invalid string op does not error" 45 | fi 46 | 47 | strmatch=$(./jp '"f"' '"f"' .eq) 48 | if [ "$strmatch" = 'true' ];then 49 | pass "test matching strings returns true" 50 | else 51 | printf -v strmatchesc "%q" "$strmatch" 52 | fail "test matching strings returns: $strmatchesc" 53 | fi 54 | 55 | strdiff=$(./jp '"f"' '"a"' .eq) 56 | if [ "$strdiff" = 'false' ];then 57 | pass "test different strings returns false" 58 | else 59 | printf -v strdiffesc "%q" "$strdiff" 60 | fail "test different strings returns: $strdiffesc" 61 | fi 62 | 63 | intmatch=$(./jp 17 17 .eq) 64 | if [ "$intmatch" = 'true' ];then 65 | pass "test matching ints returns true" 66 | else 67 | printf -v intmatchesc "%q" "$intmatch" 68 | fail "test matching ints returns: $intmatchesc" 69 | fi 70 | 71 | intdiff=$(./jp 5 43 .eq) 72 | if [ "$intdiff" = 'false' ];then 73 | pass "test different ints returns false" 74 | else 75 | printf -v intdiffesc "%q" "$intdiff" 76 | fail "test different ints returns: $intdiffesc" 77 | fi 78 | 79 | end 80 | -------------------------------------------------------------------------------- /tests/transform/uniq.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | $(./jp .uniq 2>/dev/null) 6 | if [ $? -ne 0 ];then 7 | pass "uniq on empty stack errors" 8 | else 9 | fail "uniq on empty stack does not error" 10 | fi 11 | 12 | $(./jp 1 .uniq 2>/dev/null) 13 | if [ $? -ne 0 ];then 14 | pass "uniq on non-object stack errors" 15 | else 16 | fail "uniq on non-object stack does not error" 17 | fi 18 | 19 | empty=$(./jp '{}' .uniq) 20 | if [ "$empty" = '{}' ];then 21 | pass "uniq on empty returns {}" 22 | else 23 | printf -v emptyesc "%q" "$empty" 24 | fail "uniq on empty doesn't return nothing: $emptyesc" 25 | fi 26 | 27 | two=$(./jp '{" a b c ":1,"b":2, " a b c ":3}' .uniq) 28 | if [ "$two" = $'{" a b c ":1,"b":2}' ];then 29 | pass "uniq returns two strings" 30 | else 31 | printf -v twoesc "%q" "$two" 32 | fail "uniq doesn't return two strings: $twoesc" 33 | fi 34 | 35 | cases=$(./jp '{"FOO":1,"foo":2}' .uniq) 36 | if [ "$cases" = $'{"FOO":1,"foo":2}' ];then 37 | pass "uniq ignores different case strings" 38 | else 39 | printf -v casesesc "%q" "$cases" 40 | fail "uniq doesn't ignore different case strings: $casesesc" 41 | fi 42 | 43 | end 44 | -------------------------------------------------------------------------------- /tests/transform/v.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source "test-bootstrap.bash" 3 | IFS= 4 | 5 | $(./jp .v 2>/dev/null) 6 | if [ $? -ne 0 ];then 7 | pass "v on empty stack errors" 8 | else 9 | fail "v on empty stack does not error" 10 | fi 11 | 12 | $(./jp '"f"' .v 2>/dev/null) 13 | if [ $? -ne 0 ];then 14 | pass "v on non-object errors" 15 | else 16 | fail "v on non-object does not error" 17 | fi 18 | 19 | $(./jp {} .v 2>/dev/null) 20 | if [ $? -ne 0 ];then 21 | pass "v on empty object errors" 22 | else 23 | fail "v on empty object does not error" 24 | fi 25 | 26 | empty=$(./jp '{"foo":""}' .v) 27 | if [ "$empty" = '""' ];then 28 | pass $"v on empty string val returns \"\"" 29 | else 30 | printf -v emptyesc "%q" "$empty" 31 | fail "v on empty string val returns: $emptyesc" 32 | fi 33 | 34 | null=$(./jp '{"foo":null}' .v) 35 | if [ "$null" = 'null' ];then 36 | pass $"v on null val returns null" 37 | else 38 | printf -v nullesc "%q" "$null" 39 | fail "v on null val returns: $nullesc" 40 | fi 41 | 42 | abc=$(./jp '{"abc":1}' .v) 43 | if [ "$abc" = '1' ];then 44 | pass 'v {"abc":1} returns 1' 45 | else 46 | printf -v abcesc "%q" "$abc" 47 | fail $"v {\"abc\":1} returns: $abcesc" 48 | fi 49 | 50 | nest=$(./jp '{"nest":[1,[2,[3]]]}' .v) 51 | if [ "$nest" = '[1,[2,[3]]]' ];then 52 | pass 'v {"nest":[1,[2,[3]]]} returns 1' 53 | else 54 | printf -v nestesc "%q" "$nest" 55 | fail $"v {\"nest\":[1,[2,[3]]]} returns: $nestesc" 56 | fi 57 | 58 | end 59 | --------------------------------------------------------------------------------