From 061221b073698eba39095d79aee7879895f27b5b Mon Sep 17 00:00:00 2001 From: panasenco Date: Tue, 27 Apr 2021 11:58:39 -0700 Subject: [PATCH 1/5] Alphabetized character logic in macros.rs and system_calls.rs --- crates/prolog_parser/src/macros.rs | 335 +++++++++++++++-------------- src/machine/system_calls.rs | 68 +++--- 2 files changed, 205 insertions(+), 198 deletions(-) diff --git a/crates/prolog_parser/src/macros.rs b/crates/prolog_parser/src/macros.rs index c05ed69b..f8ec9072 100644 --- a/crates/prolog_parser/src/macros.rs +++ b/crates/prolog_parser/src/macros.rs @@ -4,131 +4,6 @@ macro_rules! char_class { ($c: expr, [$head:expr $(, $cs:expr)+]) => ($c == $head || $crate::char_class!($c, [$($cs),*])); } -#[macro_export] -macro_rules! symbolic_control_char { - ($c: expr) => { - $crate::char_class!($c, ['a', 'b', 'f', 'n', 'r', 't', 'v', '0']) - }; -} - -#[macro_export] -macro_rules! space_char { - ($c: expr) => { - $c == ' ' - }; -} - -#[macro_export] -macro_rules! layout_char { - ($c: expr) => { - $crate::char_class!($c, [' ', '\n', '\t', '\u{0B}', '\u{0C}']) - }; -} - -#[macro_export] -macro_rules! symbolic_hexadecimal_char { - ($c: expr) => { - $c == 'x' - }; -} - -#[macro_export] -macro_rules! octal_digit_char { - ($c: expr) => { - ('0'..='7').contains(&$c) - }; -} - -#[macro_export] -macro_rules! binary_digit_char { - ($c: expr) => { - $c >= '0' && $c <= '1' - }; -} - -#[macro_export] -macro_rules! hexadecimal_digit_char { - ($c: expr) => { - ('0'..='9').contains(&$c) || ('A'..='F').contains(&$c) || ('a'..='f').contains(&$c) - }; -} - -#[macro_export] -macro_rules! exponent_char { - ($c: expr) => { - $c == 'e' || $c == 'E' - }; -} - -#[macro_export] -macro_rules! sign_char { - ($c: expr) => { - $c == '-' || $c == '+' - }; -} - -#[macro_export] -macro_rules! new_line_char { - ($c: expr) => { - $c == '\n' - }; -} - -#[macro_export] -macro_rules! end_line_comment_char { - ($c: expr) => { - $c == '%' - }; -} - -#[macro_export] -macro_rules! comment_1_char { - ($c: expr) => { - $c == '/' - }; -} - -#[macro_export] -macro_rules! comment_2_char { - ($c: expr) => { - $c == '*' - }; -} - -#[macro_export] -macro_rules! capital_letter_char { - ($c: expr) => { - ('A'..='Z').contains(&$c) - }; -} - -#[macro_export] -macro_rules! small_letter_char { - ($c: expr) => { - ('a'..='z').contains(&$c) - }; -} - -#[macro_export] -macro_rules! variable_indicator_char { - ($c: expr) => { - $c == '_' - }; -} - -#[macro_export] -macro_rules! graphic_char { - ($c: expr) => ($crate::char_class!($c, ['#', '$', '&', '*', '+', '-', '.', '/', ':', - '<', '=', '>', '?', '@', '^', '~'])) -} - -#[macro_export] -macro_rules! graphic_token_char { - ($c: expr) => { - $crate::graphic_char!($c) || $crate::backslash_char!($c) - }; -} - #[macro_export] macro_rules! alpha_char { ($c: expr) => { @@ -157,6 +32,62 @@ macro_rules! alpha_char { }; } +#[macro_export] +macro_rules! alpha_numeric_char { + ($c: expr) => { + $crate::alpha_char!($c) || $crate::decimal_digit_char!($c) + }; +} + +#[macro_export] +macro_rules! backslash_char { + ($c: expr) => { + $c == '\\' + }; +} + +#[macro_export] +macro_rules! back_quote_char { + ($c: expr) => { + $c == '`' + }; +} + +#[macro_export] +macro_rules! binary_digit_char { + ($c: expr) => { + $c >= '0' && $c <= '1' + }; +} + +#[macro_export] +macro_rules! capital_letter_char { + ($c: expr) => { + ('A'..='Z').contains(&$c) + }; +} + +#[macro_export] +macro_rules! comment_1_char { + ($c: expr) => { + $c == '/' + }; +} + +#[macro_export] +macro_rules! comment_2_char { + ($c: expr) => { + $c == '*' + }; +} + +#[macro_export] +macro_rules! cut_char { + ($c: expr) => { + $c == '!' + }; +} + #[macro_export] macro_rules! decimal_digit_char { ($c: expr) => { @@ -171,41 +102,6 @@ macro_rules! decimal_point_char { }; } -#[macro_export] -macro_rules! alpha_numeric_char { - ($c: expr) => { - $crate::alpha_char!($c) || $crate::decimal_digit_char!($c) - }; -} - -#[macro_export] -macro_rules! cut_char { - ($c: expr) => { - $c == '!' - }; -} - -#[macro_export] -macro_rules! semicolon_char { - ($c: expr) => { - $c == ';' - }; -} - -#[macro_export] -macro_rules! backslash_char { - ($c: expr) => { - $c == '\\' - }; -} - -#[macro_export] -macro_rules! single_quote_char { - ($c: expr) => { - $c == '\'' - }; -} - #[macro_export] macro_rules! double_quote_char { ($c: expr) => { @@ -214,9 +110,43 @@ macro_rules! double_quote_char { } #[macro_export] -macro_rules! back_quote_char { +macro_rules! end_line_comment_char { ($c: expr) => { - $c == '`' + $c == '%' + }; +} + +#[macro_export] +macro_rules! exponent_char { + ($c: expr) => { + $c == 'e' || $c == 'E' + }; +} + +#[macro_export] +macro_rules! graphic_char { + ($c: expr) => ($crate::char_class!($c, ['#', '$', '&', '*', '+', '-', '.', '/', ':', + '<', '=', '>', '?', '@', '^', '~'])) +} + +#[macro_export] +macro_rules! graphic_token_char { + ($c: expr) => { + $crate::graphic_char!($c) || $crate::backslash_char!($c) + }; +} + +#[macro_export] +macro_rules! hexadecimal_digit_char { + ($c: expr) => { + ('0'..='9').contains(&$c) || ('A'..='F').contains(&$c) || ('a'..='f').contains(&$c) + }; +} + +#[macro_export] +macro_rules! layout_char { + ($c: expr) => { + $crate::char_class!($c, [' ', '\n', '\t', '\u{0B}', '\u{0C}']) }; } @@ -228,9 +158,23 @@ macro_rules! meta_char { } #[macro_export] -macro_rules! solo_char { +macro_rules! new_line_char { ($c: expr) => { - $crate::char_class!($c, ['!', '(', ')', ',', ';', '[', ']', '{', '}', '|', '%']) + $c == '\n' + }; +} + +#[macro_export] +macro_rules! octal_digit_char { + ($c: expr) => { + ('0'..='7').contains(&$c) + }; +} + +#[macro_export] +macro_rules! octet_char { + ($c: expr) => { + ('\u{0000}'..='\u{00FF}').contains(&$c) }; } @@ -244,3 +188,66 @@ macro_rules! prolog_char { || $crate::meta_char!($c) }; } + +#[macro_export] +macro_rules! semicolon_char { + ($c: expr) => { + $c == ';' + }; +} + +#[macro_export] +macro_rules! sign_char { + ($c: expr) => { + $c == '-' || $c == '+' + }; +} + +#[macro_export] +macro_rules! single_quote_char { + ($c: expr) => { + $c == '\'' + }; +} + +#[macro_export] +macro_rules! small_letter_char { + ($c: expr) => { + ('a'..='z').contains(&$c) + }; +} + +#[macro_export] +macro_rules! solo_char { + ($c: expr) => { + $crate::char_class!($c, ['!', '(', ')', ',', ';', '[', ']', '{', '}', '|', '%']) + }; +} + +#[macro_export] +macro_rules! space_char { + ($c: expr) => { + $c == ' ' + }; +} + +#[macro_export] +macro_rules! symbolic_control_char { + ($c: expr) => { + $crate::char_class!($c, ['a', 'b', 'f', 'n', 'r', 't', 'v', '0']) + }; +} + +#[macro_export] +macro_rules! symbolic_hexadecimal_char { + ($c: expr) => { + $c == 'x' + }; +} + +#[macro_export] +macro_rules! variable_indicator_char { + ($c: expr) => { + $c == '_' + }; +} diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 082a3e16..428230ca 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -1775,46 +1775,46 @@ impl MachineState { } }; } - macro_check!(symbolic_control_char, "symbolic_control"); - // macro_check!(space_char, "space"); - macro_check!(layout_char, "layout"); - macro_check!(symbolic_hexadecimal_char, "symbolic_hexadecimal"); - macro_check!(octal_digit_char, "octal_digit"); - macro_check!(binary_digit_char, "binary_digit"); - macro_check!(hexadecimal_digit_char, "hexadecimal_digit"); - macro_check!(exponent_char, "exponent"); - macro_check!(sign_char, "sign"); - // macro_check!(new_line_char, "new_line"); - // macro_check!(comment_1_char, "comment_1"); - // macro_check!(comment_2_char, "comment_2"); - // macro_check!(capital_letter_char, "upper"); - // macro_check!(small_letter_char, "lower"); - // macro_check!(variable_indicator_char, "variable_indicator"); - macro_check!(graphic_char, "graphic"); - macro_check!(graphic_token_char, "graphic_token"); macro_check!(alpha_char, "alpha"); - macro_check!(decimal_digit_char, "decimal_digit"); - // macro_check!(decimal_point_char, "decimal_point"); - macro_check!(alpha_numeric_char, "alnum"); - // macro_check!(cut_char, "cut"); - // macro_check!(semicolon_char, "semicolon"); - // macro_check!(backslash_char, "backslash"); - // macro_check!(single_quote_char, "single_quote"); - // macro_check!(double_quote_char, "double_quote"); - // macro_check!(back_quote_char, "back_quote"); - macro_check!(meta_char, "meta"); - macro_check!(solo_char, "solo"); - macro_check!(prolog_char, "prolog"); method_check!(is_alphabetic, "alphabetic"); - method_check!(is_lowercase, "lower"); - method_check!(is_uppercase, "upper"); - method_check!(is_whitespace, "whitespace"); method_check!(is_alphanumeric, "alphanumeric"); - method_check!(is_control, "control"); - method_check!(is_numeric, "numeric"); + macro_check!(alpha_numeric_char, "alnum"); method_check!(is_ascii, "ascii"); method_check!(is_ascii_punctuation, "ascii_ponctuaction"); method_check!(is_ascii_graphic, "ascii_graphic"); + // macro_check!(backslash_char, "backslash"); + // macro_check!(back_quote_char, "back_quote"); + macro_check!(binary_digit_char, "binary_digit"); + // macro_check!(capital_letter_char, "upper"); + // macro_check!(comment_1_char, "comment_1"); + // macro_check!(comment_2_char, "comment_2"); + method_check!(is_control, "control"); + // macro_check!(cut_char, "cut"); + macro_check!(decimal_digit_char, "decimal_digit"); + // macro_check!(decimal_point_char, "decimal_point"); + // macro_check!(double_quote_char, "double_quote"); + macro_check!(exponent_char, "exponent"); + macro_check!(graphic_char, "graphic"); + macro_check!(graphic_token_char, "graphic_token"); + macro_check!(hexadecimal_digit_char, "hexadecimal_digit"); + macro_check!(layout_char, "layout"); + method_check!(is_lowercase, "lower"); + macro_check!(meta_char, "meta"); + // macro_check!(new_line_char, "new_line"); + method_check!(is_numeric, "numeric"); + macro_check!(octal_digit_char, "octal_digit"); + macro_check!(prolog_char, "prolog"); + // macro_check!(semicolon_char, "semicolon"); + macro_check!(sign_char, "sign"); + // macro_check!(single_quote_char, "single_quote"); + // macro_check!(small_letter_char, "lower"); + macro_check!(solo_char, "solo"); + // macro_check!(space_char, "space"); + macro_check!(symbolic_hexadecimal_char, "symbolic_hexadecimal"); + macro_check!(symbolic_control_char, "symbolic_control"); + method_check!(is_uppercase, "upper"); + // macro_check!(variable_indicator_char, "variable_indicator"); + method_check!(is_whitespace, "whitespace"); } &SystemClauseType::CheckCutPoint => { let addr = self.store(self.deref(self[temp_v!(1)])); From 0198fe90b6ba38e7a2cad9cd3a2739740c9086c6 Mon Sep 17 00:00:00 2001 From: panasenco Date: Tue, 27 Apr 2021 22:48:03 -0700 Subject: [PATCH 2/5] Added ABNF grammar to library(charsio) as well as octet character type that it depends on. Modified library(json) to use the new ABNF grammar. --- src/lib/charsio.pl | 128 +++++++++++++++++++++++- src/lib/json.pl | 28 ++---- src/machine/system_calls.rs | 3 +- src/tests/json/pass_everything.min.json | 2 +- src/tests/json/test_json.pl | 5 +- 5 files changed, 139 insertions(+), 27 deletions(-) diff --git a/src/lib/charsio.pl b/src/lib/charsio.pl index abd30311..599b892d 100644 --- a/src/lib/charsio.pl +++ b/src/lib/charsio.pl @@ -4,7 +4,23 @@ read_line_to_chars/3, read_term_from_chars/2, write_term_to_chars/3, - chars_base64/3]). + chars_base64/3, + abnf_alpha//1, + abnf_bit//1, + abnf_char//1, + abnf_cr//0, + abnf_crlf//0, + abnf_ctl//1, + abnf_digit//1, + abnf_dquote//0, + abnf_hexdig//1, + abnf_htab//0, + abnf_lf//0, + abnf_lwsp//0, + abnf_octet//1, + abnf_sp//0, + abnf_vchar//1, + abnf_wsp//0 ]). :- use_module(library(dcgs)). :- use_module(library(iso_ext)). @@ -97,6 +113,7 @@ ctype(lower). ctype(meta). ctype(numeric). ctype(octal_digit). +ctype(octet). ctype(prolog). ctype(sign). ctype(solo). @@ -241,3 +258,112 @@ chars_base64(Cs, Bs, Options) :- maplist(must_be(character), Cs), '$chars_base64'(Cs, Bs, Padding, Charset) ). + +/* [Core Rules](https://tools.ietf.org/html/rfc5234#appendix-B.1) of the + Augmented Backus-Naur Form specification (ABNF - RFC 5234). ABNF commonly + serves as the definition language for IETF communication protocols, so + having these DCGs can be extremely useful for reasoning about most IETF + syntaxes. The DCGs are presented in the order they appear in the RFC. + While some DCGs below use `char_type/2`, the most common ones are defined + manually in order to take advantage of Prolog's first-argument indexing. */ +abnf_alpha('a') --> "a". +abnf_alpha('b') --> "b". +abnf_alpha('c') --> "c". +abnf_alpha('d') --> "d". +abnf_alpha('e') --> "e". +abnf_alpha('f') --> "f". +abnf_alpha('g') --> "g". +abnf_alpha('h') --> "h". +abnf_alpha('i') --> "i". +abnf_alpha('j') --> "j". +abnf_alpha('k') --> "k". +abnf_alpha('l') --> "l". +abnf_alpha('m') --> "m". +abnf_alpha('n') --> "n". +abnf_alpha('o') --> "o". +abnf_alpha('p') --> "p". +abnf_alpha('q') --> "q". +abnf_alpha('r') --> "r". +abnf_alpha('s') --> "s". +abnf_alpha('t') --> "t". +abnf_alpha('u') --> "u". +abnf_alpha('v') --> "v". +abnf_alpha('w') --> "w". +abnf_alpha('x') --> "x". +abnf_alpha('y') --> "y". +abnf_alpha('z') --> "z". +abnf_alpha('A') --> "A". +abnf_alpha('B') --> "B". +abnf_alpha('C') --> "C". +abnf_alpha('D') --> "D". +abnf_alpha('E') --> "E". +abnf_alpha('F') --> "F". +abnf_alpha('G') --> "G". +abnf_alpha('H') --> "H". +abnf_alpha('I') --> "I". +abnf_alpha('J') --> "J". +abnf_alpha('K') --> "K". +abnf_alpha('L') --> "L". +abnf_alpha('M') --> "M". +abnf_alpha('N') --> "N". +abnf_alpha('O') --> "O". +abnf_alpha('P') --> "P". +abnf_alpha('Q') --> "Q". +abnf_alpha('R') --> "R". +abnf_alpha('S') --> "S". +abnf_alpha('T') --> "T". +abnf_alpha('U') --> "U". +abnf_alpha('V') --> "V". +abnf_alpha('W') --> "W". +abnf_alpha('X') --> "X". +abnf_alpha('Y') --> "Y". +abnf_alpha('Z') --> "Z". + +abnf_bit(0) --> "0". +abnf_bit(1) --> "1". + +abnf_char(C) --> [C], { dif(C, '\x0000\'), char_type(C, ascii) }. %' + +abnf_cr --> "\r". + +abnf_crlf --> "\r\n". + +abnf_ctl(C) --> [C], { char_type(C, ascii), char_type(C, control) }. + +abnf_digit(0) --> "0". +abnf_digit(1) --> "1". +abnf_digit(2) --> "2". +abnf_digit(3) --> "3". +abnf_digit(4) --> "4". +abnf_digit(5) --> "5". +abnf_digit(6) --> "6". +abnf_digit(7) --> "7". +abnf_digit(8) --> "8". +abnf_digit(9) --> "9". + +abnf_dquote --> "\"". + +abnf_hexdig(Digit) --> abnf_digit(Digit). +abnf_hexdig(10) --> "A". +abnf_hexdig(11) --> "B". +abnf_hexdig(12) --> "C". +abnf_hexdig(13) --> "D". +abnf_hexdig(14) --> "E". +abnf_hexdig(15) --> "F". + +abnf_htab --> "\t". + +abnf_lf --> "\n". + +abnf_lwsp --> "". +abnf_lwsp --> abnf_wsp, abnf_lwsp. +abnf_lwsp --> abnf_clrf, abnf_wsp, abnf_lwsp. + +abnf_octet(C) --> [C], char_type(C, octet). + +abnf_sp --> " ". + +abnf_vchar(C) --> [C], char_type(C, ascii_graphic). + +abnf_wsp --> abnf_sp. +abnf_wsp --> abnf_htab. diff --git a/src/lib/json.pl b/src/lib/json.pl index 2d7787d8..ff980d7f 100644 --- a/src/lib/json.pl +++ b/src/lib/json.pl @@ -37,6 +37,7 @@ json_chars//1 ]). +:- use_module(library(charsio)). :- use_module(library(dcgs)). :- use_module(library(dif)). :- use_module(library(lists)). @@ -161,19 +162,13 @@ json_character(EscapeChar) --> H4 is (EscapeCharCode // 16^0) mod 16 ) }. -json_hex(Digit) --> json_digit(Digit). +json_hex(Hex) --> abnf_hexdig(Hex). json_hex(10) --> "a". json_hex(11) --> "b". json_hex(12) --> "c". json_hex(13) --> "d". json_hex(14) --> "e". json_hex(15) --> "f". -json_hex(10) --> "A". -json_hex(11) --> "B". -json_hex(12) --> "C". -json_hex(13) --> "D". -json_hex(14) --> "E". -json_hex(15) --> "F". /* I can't think of any alternatives to using `number_chars/2` when generating, though this leads to under-reporting of correct solutions. At least matching solutions unify when both are instantiated... @@ -205,31 +200,20 @@ json_number(Number) --> NumberChars ). -json_integer(Digit) --> json_digit(Digit). +json_integer(Digit) --> abnf_digit(Digit). json_integer(TotalValue) --> json_onenine(FirstDigit), json_digits(RemainingValue, Power), { TotalValue is FirstDigit * 10 ^ (Power + 1) + RemainingValue }. -json_digits(Digit, 0) --> json_digit(Digit). +json_digits(Digit, 0) --> abnf_digit(Digit). json_digits(Value, Power) --> - json_digit(FirstDigit), + abnf_digit(FirstDigit), json_digits(RemainingValue, NextPower), { Power is NextPower + 1, Value is FirstDigit * 10^Power + RemainingValue }. -json_digit(0) --> "0". -json_digit(Digit) --> json_onenine(Digit). - -json_onenine(1) --> "1". -json_onenine(2) --> "2". -json_onenine(3) --> "3". -json_onenine(4) --> "4". -json_onenine(5) --> "5". -json_onenine(6) --> "6". -json_onenine(7) --> "7". -json_onenine(8) --> "8". -json_onenine(9) --> "9". +json_onenine(Digit) --> abnf_digit(Digit), { dif(Digit, 0) }. json_fraction(0) --> "". json_fraction(Fraction) --> diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 428230ca..00aa6d6e 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -3,7 +3,7 @@ use prolog_parser::parser::*; use prolog_parser::{ alpha_char, alpha_numeric_char, binary_digit_char, clause_name, decimal_digit_char, exponent_char, graphic_char, graphic_token_char, hexadecimal_digit_char, layout_char, - meta_char, new_line_char, octal_digit_char, prolog_char, sign_char, solo_char, + meta_char, new_line_char, octal_digit_char, octet_char, prolog_char, sign_char, solo_char, symbolic_control_char, symbolic_hexadecimal_char, temp_v, }; @@ -1803,6 +1803,7 @@ impl MachineState { // macro_check!(new_line_char, "new_line"); method_check!(is_numeric, "numeric"); macro_check!(octal_digit_char, "octal_digit"); + macro_check!(octet_char, "octet"); macro_check!(prolog_char, "prolog"); // macro_check!(semicolon_char, "semicolon"); macro_check!(sign_char, "sign"); diff --git a/src/tests/json/pass_everything.min.json b/src/tests/json/pass_everything.min.json index e474c5dc..5d5659ea 100644 --- a/src/tests/json/pass_everything.min.json +++ b/src/tests/json/pass_everything.min.json @@ -1 +1 @@ -["JSON Test Pattern pass1",{"object with 1 member":["array with 1 element"]},{},[],-42,true,false,null,{"integer":1234567890,"real":-9876.54321,"e":0.000000000000123456789,"E":12345678900000000000000000000000000.0,"":23456789012000000000000000000000000000000000000000000000000000000000000000000,"zero":0,"one":1,"space":" ","quote":"\"","backslash":"\\","controls":"\b\f\n\r\t","slash":"\/ & \/","alpha":"abcdefghijklmnopqrstuvwyz","ALPHA":"ABCDEFGHIJKLMNOPQRSTUVWYZ","digit":"0123456789","special":"`1~!@#$%^&*()_+-={':[,]}|;.<\/>?","hex":"ģ䕧覫\u0001췯ꯍ\u001a","true":true,"false":false,"null":null,"array":[],"object":{},"address":"50 St. James Street","url":"http:\/\/www.JSON.org\/","comment":"\/\/ \/* *\/":" "," s p a c e d ":[1,2,3,4,5,6,7],"compact":[1,2,3,4,5,6,7],"jsontext":"{\"object with 1 member\":[\"array with 1 element\"]}","quotes":"" \" %22 0x22 034 "","\/\\\"쫾몾ꮘﳞ볚\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',.\/<>?":"A key can be any string"},0.5,98.6,99.44,1066,"rosebud"] \ No newline at end of file +["JSON Test Pattern pass1",{"object with 1 member":["array with 1 element"]},{},[],-42,true,false,null,{"integer":1234567890,"real":-9876.54321,"e":0.000000000000123456789,"E":12345678900000000000000000000000000.0,"":23456789012000000000000000000000000000000000000000000000000000000000000000000,"zero":0,"one":1,"space":" ","quote":"\"","backslash":"\\","controls":"\b\f\n\r\t","slash":"\/ & \/","alpha":"abcdefghijklmnopqrstuvwyz","ALPHA":"ABCDEFGHIJKLMNOPQRSTUVWYZ","digit":"0123456789","special":"`1~!@#$%^&*()_+-={':[,]}|;.<\/>?","hex":"ģ䕧覫\u0001췯ꯍ\u001A","true":true,"false":false,"null":null,"array":[],"object":{},"address":"50 St. James Street","url":"http:\/\/www.JSON.org\/","comment":"\/\/ \/* *\/":" "," s p a c e d ":[1,2,3,4,5,6,7],"compact":[1,2,3,4,5,6,7],"jsontext":"{\"object with 1 member\":[\"array with 1 element\"]}","quotes":"" \" %22 0x22 034 "","\/\\\"쫾몾ꮘﳞ볚\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',.\/<>?":"A key can be any string"},0.5,98.6,99.44,1066,"rosebud"] diff --git a/src/tests/json/test_json.pl b/src/tests/json/test_json.pl index e41688ca..441e7cd5 100644 --- a/src/tests/json/test_json.pl +++ b/src/tests/json/test_json.pl @@ -36,7 +36,7 @@ minify_sample_json :- test_path("pass_everything.min.json", MinPath), setup_call_cleanup( open(MinPath, write, Stream), - format(Stream, "~s", [MinChars]), + format(Stream, "~s~n", [MinChars]), close(Stream) ). @@ -45,7 +45,8 @@ test_json_minify :- once(phrase_from_file(seq(RefChars), MinPath)), name_parse("pass_everything.json", Json), time(once(phrase(json_chars(Json), MinChars))), - RefChars = MinChars. + append(MinChars, "\n", MinFileChars), + RefChars = MinFileChars. test_json_int_float :- once(phrase(json_chars(number(ZeroInt)), "0")), From cb07074246f31b343bd1107b923d7cc0f71fef43 Mon Sep 17 00:00:00 2001 From: panasenco Date: Wed, 28 Apr 2021 16:09:38 -0700 Subject: [PATCH 3/5] Replaced object() with pairs() in library(json), and made key type explicit. --- src/lib/json.pl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/json.pl b/src/lib/json.pl index ff980d7f..5f5ff6c1 100644 --- a/src/lib/json.pl +++ b/src/lib/json.pl @@ -50,8 +50,8 @@ json_chars(Internal) --> json_element(Internal). different types of values based on their principal functor. The principal functors match the types defined in the JSON Schema spec here: https://json-schema.org/draft/2020-12/json-schema-validation.html#rfc.section.6.1.1 EXCEPT we don't yet support the integer type. There are plans for more JSON Schema support in the near future. */ -json_value(object(Assoc)) --> json_object(Assoc). -json_value(array(List)) --> json_array(List). +json_value(pairs(Pairs)) --> json_object(Pairs). +json_value(list(List)) --> json_array(List). json_value(string(Chars)) --> json_string(Chars). json_value(number(Number)) --> json_number(Number). json_value(boolean(Bool)) --> json_boolean(Bool). @@ -83,7 +83,7 @@ json_members([NextPair|Pairs], Key-Value) --> ",", json_members(Pairs, NextPair). -json_member(Key, Value) --> json_ws, json_string(Key), json_ws, ":", json_element(Value). +json_member(string(Key), Value) --> json_ws, json_string(Key), json_ws, ":", json_element(Value). json_array([]) --> "[", json_ws, "]". json_array([Value|Values]) --> "[", json_elements(Values, Value), "]". From dfbf29172523d168679c375b7f9e6e20db9577e6 Mon Sep 17 00:00:00 2001 From: panasenco Date: Wed, 28 Apr 2021 22:22:00 -0700 Subject: [PATCH 4/5] Restructuring and improving documentation. --- README.md | 13 ++- src/lib/charsio.pl | 127 +-------------------- src/lib/serialization/abnf.pl | 166 ++++++++++++++++++++++++++++ src/lib/{ => serialization}/json.pl | 5 +- src/tests/json/test_json.pl | 4 +- 5 files changed, 184 insertions(+), 131 deletions(-) create mode 100644 src/lib/serialization/abnf.pl rename src/lib/{ => serialization}/json.pl (97%) diff --git a/README.md b/README.md index c788e3e9..8da7f4d3 100644 --- a/README.md +++ b/README.md @@ -518,6 +518,17 @@ The modules that ship with Scryer Prolog are also called * [`csv`](src/lib/csv.pl) `parse_csv//1` and `parse_csv//2` can be used with [`phrase_from_file/2`](src/lib/pio.pl) or [`phrase/2`](src/lib/dcgs.pl) to parse csv +* [`serialization/abnf`](src/lib/serialization/abnf.pl) + DCGs describing the + [ABNF grammar core (RFC 5234)](https://tools.ietf.org/html/rfc5234#appendix-B.1), + which is used to describe many [IETF](https://www.ietf.org/standards/rfcs/) + syntaxes, such as [HTTP v1.1](https://www.rfc-editor.org/rfc/rfc7230.html#page-82), + [SMTP](https://www.rfc-editor.org/rfc/rfc5321.html), + [iCalendar](https://www.rfc-editor.org/rfc/rfc5545.html), and more. +* [`serialization/json`](src/lib/serialization/json.pl) + `json_chars//1` can be used with [`phrase_from_file/2`](src/lib/pio.pl) + or [`phrase/2`](src/lib/dcgs.pl) to parse and generate + [JSON](https://www.json.org/json-en.html). * [`xpath`](src/lib/xpath.pl) The predicate `xpath/3` is used for convenient reasoning about HTML and XML documents, inspired by the XPath language. This library @@ -539,8 +550,6 @@ The modules that ship with Scryer Prolog are also called ECDH key exchange over Curve25519 (X25519), authenticated symmetric encryption with ChaCha20-Poly1305, and reasoning about elliptic curves. * [`uuid`](src/lib/uuid.pl) UUIDv4 generation and hex representation -* [`json`](src/lib/json.pl) [JSON](https://www.json.org/json-en.html) - parsing and generation (beta version, subject to interface changes). To use predicates provided by the `lists` library, write: diff --git a/src/lib/charsio.pl b/src/lib/charsio.pl index 599b892d..d186eaf4 100644 --- a/src/lib/charsio.pl +++ b/src/lib/charsio.pl @@ -4,23 +4,7 @@ read_line_to_chars/3, read_term_from_chars/2, write_term_to_chars/3, - chars_base64/3, - abnf_alpha//1, - abnf_bit//1, - abnf_char//1, - abnf_cr//0, - abnf_crlf//0, - abnf_ctl//1, - abnf_digit//1, - abnf_dquote//0, - abnf_hexdig//1, - abnf_htab//0, - abnf_lf//0, - abnf_lwsp//0, - abnf_octet//1, - abnf_sp//0, - abnf_vchar//1, - abnf_wsp//0 ]). + chars_base64/3]). :- use_module(library(dcgs)). :- use_module(library(iso_ext)). @@ -258,112 +242,3 @@ chars_base64(Cs, Bs, Options) :- maplist(must_be(character), Cs), '$chars_base64'(Cs, Bs, Padding, Charset) ). - -/* [Core Rules](https://tools.ietf.org/html/rfc5234#appendix-B.1) of the - Augmented Backus-Naur Form specification (ABNF - RFC 5234). ABNF commonly - serves as the definition language for IETF communication protocols, so - having these DCGs can be extremely useful for reasoning about most IETF - syntaxes. The DCGs are presented in the order they appear in the RFC. - While some DCGs below use `char_type/2`, the most common ones are defined - manually in order to take advantage of Prolog's first-argument indexing. */ -abnf_alpha('a') --> "a". -abnf_alpha('b') --> "b". -abnf_alpha('c') --> "c". -abnf_alpha('d') --> "d". -abnf_alpha('e') --> "e". -abnf_alpha('f') --> "f". -abnf_alpha('g') --> "g". -abnf_alpha('h') --> "h". -abnf_alpha('i') --> "i". -abnf_alpha('j') --> "j". -abnf_alpha('k') --> "k". -abnf_alpha('l') --> "l". -abnf_alpha('m') --> "m". -abnf_alpha('n') --> "n". -abnf_alpha('o') --> "o". -abnf_alpha('p') --> "p". -abnf_alpha('q') --> "q". -abnf_alpha('r') --> "r". -abnf_alpha('s') --> "s". -abnf_alpha('t') --> "t". -abnf_alpha('u') --> "u". -abnf_alpha('v') --> "v". -abnf_alpha('w') --> "w". -abnf_alpha('x') --> "x". -abnf_alpha('y') --> "y". -abnf_alpha('z') --> "z". -abnf_alpha('A') --> "A". -abnf_alpha('B') --> "B". -abnf_alpha('C') --> "C". -abnf_alpha('D') --> "D". -abnf_alpha('E') --> "E". -abnf_alpha('F') --> "F". -abnf_alpha('G') --> "G". -abnf_alpha('H') --> "H". -abnf_alpha('I') --> "I". -abnf_alpha('J') --> "J". -abnf_alpha('K') --> "K". -abnf_alpha('L') --> "L". -abnf_alpha('M') --> "M". -abnf_alpha('N') --> "N". -abnf_alpha('O') --> "O". -abnf_alpha('P') --> "P". -abnf_alpha('Q') --> "Q". -abnf_alpha('R') --> "R". -abnf_alpha('S') --> "S". -abnf_alpha('T') --> "T". -abnf_alpha('U') --> "U". -abnf_alpha('V') --> "V". -abnf_alpha('W') --> "W". -abnf_alpha('X') --> "X". -abnf_alpha('Y') --> "Y". -abnf_alpha('Z') --> "Z". - -abnf_bit(0) --> "0". -abnf_bit(1) --> "1". - -abnf_char(C) --> [C], { dif(C, '\x0000\'), char_type(C, ascii) }. %' - -abnf_cr --> "\r". - -abnf_crlf --> "\r\n". - -abnf_ctl(C) --> [C], { char_type(C, ascii), char_type(C, control) }. - -abnf_digit(0) --> "0". -abnf_digit(1) --> "1". -abnf_digit(2) --> "2". -abnf_digit(3) --> "3". -abnf_digit(4) --> "4". -abnf_digit(5) --> "5". -abnf_digit(6) --> "6". -abnf_digit(7) --> "7". -abnf_digit(8) --> "8". -abnf_digit(9) --> "9". - -abnf_dquote --> "\"". - -abnf_hexdig(Digit) --> abnf_digit(Digit). -abnf_hexdig(10) --> "A". -abnf_hexdig(11) --> "B". -abnf_hexdig(12) --> "C". -abnf_hexdig(13) --> "D". -abnf_hexdig(14) --> "E". -abnf_hexdig(15) --> "F". - -abnf_htab --> "\t". - -abnf_lf --> "\n". - -abnf_lwsp --> "". -abnf_lwsp --> abnf_wsp, abnf_lwsp. -abnf_lwsp --> abnf_clrf, abnf_wsp, abnf_lwsp. - -abnf_octet(C) --> [C], char_type(C, octet). - -abnf_sp --> " ". - -abnf_vchar(C) --> [C], char_type(C, ascii_graphic). - -abnf_wsp --> abnf_sp. -abnf_wsp --> abnf_htab. diff --git a/src/lib/serialization/abnf.pl b/src/lib/serialization/abnf.pl new file mode 100644 index 00000000..40e5d9f6 --- /dev/null +++ b/src/lib/serialization/abnf.pl @@ -0,0 +1,166 @@ +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Written Apr 2021 by Aram Panasenco (panasenco@ucla.edu) + Part of Scryer Prolog. + + [Core Rules](https://tools.ietf.org/html/rfc5234#appendix-B.1) of the + Augmented Backus-Naur Form specification (ABNF - RFC 5234). ABNF commonly + serves as the definition language for IETF communication protocols, so + having these DCGs can be extremely useful for reasoning about most IETF + syntaxes. The DCGs are presented in the order they appear in the RFC. + While some DCGs below use `char_type/2`, the most common ones are defined + manually in order to take advantage of Prolog's first-argument indexing. + + BSD 3-Clause License + + Copyright (c) 2021, Aram Panasenco + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +:- module(abnf, [abnf_alpha//1, + abnf_bit//1, + abnf_char//1, + abnf_cr//0, + abnf_crlf//0, + abnf_ctl//1, + abnf_digit//1, + abnf_dquote//0, + abnf_hexdig//1, + abnf_htab//0, + abnf_lf//0, + abnf_lwsp//0, + abnf_octet//1, + abnf_sp//0, + abnf_vchar//1, + abnf_wsp//0 ]). + +:- use_module(library(charsio)). +:- use_module(library(dcgs)). +:- use_module(library(dif)). +:- use_module(library(lists)). + +abnf_alpha('a') --> "a". +abnf_alpha('b') --> "b". +abnf_alpha('c') --> "c". +abnf_alpha('d') --> "d". +abnf_alpha('e') --> "e". +abnf_alpha('f') --> "f". +abnf_alpha('g') --> "g". +abnf_alpha('h') --> "h". +abnf_alpha('i') --> "i". +abnf_alpha('j') --> "j". +abnf_alpha('k') --> "k". +abnf_alpha('l') --> "l". +abnf_alpha('m') --> "m". +abnf_alpha('n') --> "n". +abnf_alpha('o') --> "o". +abnf_alpha('p') --> "p". +abnf_alpha('q') --> "q". +abnf_alpha('r') --> "r". +abnf_alpha('s') --> "s". +abnf_alpha('t') --> "t". +abnf_alpha('u') --> "u". +abnf_alpha('v') --> "v". +abnf_alpha('w') --> "w". +abnf_alpha('x') --> "x". +abnf_alpha('y') --> "y". +abnf_alpha('z') --> "z". +abnf_alpha('A') --> "A". +abnf_alpha('B') --> "B". +abnf_alpha('C') --> "C". +abnf_alpha('D') --> "D". +abnf_alpha('E') --> "E". +abnf_alpha('F') --> "F". +abnf_alpha('G') --> "G". +abnf_alpha('H') --> "H". +abnf_alpha('I') --> "I". +abnf_alpha('J') --> "J". +abnf_alpha('K') --> "K". +abnf_alpha('L') --> "L". +abnf_alpha('M') --> "M". +abnf_alpha('N') --> "N". +abnf_alpha('O') --> "O". +abnf_alpha('P') --> "P". +abnf_alpha('Q') --> "Q". +abnf_alpha('R') --> "R". +abnf_alpha('S') --> "S". +abnf_alpha('T') --> "T". +abnf_alpha('U') --> "U". +abnf_alpha('V') --> "V". +abnf_alpha('W') --> "W". +abnf_alpha('X') --> "X". +abnf_alpha('Y') --> "Y". +abnf_alpha('Z') --> "Z". + +abnf_bit(0) --> "0". +abnf_bit(1) --> "1". + +abnf_char(C) --> [C], { dif(C, '\x0000\'), char_type(C, ascii) }. %' + +abnf_cr --> "\r". + +abnf_crlf --> "\r\n". + +abnf_ctl(C) --> [C], { char_type(C, ascii), char_type(C, control) }. + +abnf_digit(0) --> "0". +abnf_digit(1) --> "1". +abnf_digit(2) --> "2". +abnf_digit(3) --> "3". +abnf_digit(4) --> "4". +abnf_digit(5) --> "5". +abnf_digit(6) --> "6". +abnf_digit(7) --> "7". +abnf_digit(8) --> "8". +abnf_digit(9) --> "9". + +abnf_dquote --> "\"". + +abnf_hexdig(Digit) --> abnf_digit(Digit). +abnf_hexdig(10) --> "A". +abnf_hexdig(11) --> "B". +abnf_hexdig(12) --> "C". +abnf_hexdig(13) --> "D". +abnf_hexdig(14) --> "E". +abnf_hexdig(15) --> "F". + +abnf_htab --> "\t". + +abnf_lf --> "\n". + +abnf_lwsp --> "". +abnf_lwsp --> abnf_wsp, abnf_lwsp. +abnf_lwsp --> abnf_clrf, abnf_wsp, abnf_lwsp. + +abnf_octet(C) --> [C], char_type(C, octet). + +abnf_sp --> " ". + +abnf_vchar(C) --> [C], char_type(C, ascii_graphic). + +abnf_wsp --> abnf_sp. +abnf_wsp --> abnf_htab. diff --git a/src/lib/json.pl b/src/lib/serialization/json.pl similarity index 97% rename from src/lib/json.pl rename to src/lib/serialization/json.pl index 5f5ff6c1..50672e1f 100644 --- a/src/lib/json.pl +++ b/src/lib/serialization/json.pl @@ -1,6 +1,9 @@ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Written Apr 2021 by Aram Panasenco (panasenco@ucla.edu) Part of Scryer Prolog. + + `json_chars//1` can be used with [`phrase_from_file/2`](src/lib/pio.pl) + or [`phrase/2`](src/lib/dcgs.pl) to parse and generate [JSON](https://www.json.org/json-en.html). BSD 3-Clause License @@ -37,10 +40,10 @@ json_chars//1 ]). -:- use_module(library(charsio)). :- use_module(library(dcgs)). :- use_module(library(dif)). :- use_module(library(lists)). +:- use_module(library(serialization/abnf)). /* The DCGs are written to match the McKeeman form presented on the right side of https://www.json.org/json-en.html as closely as possible. Note that the names in the McKeeman form conflict with the pictures on the site. */ diff --git a/src/tests/json/test_json.pl b/src/tests/json/test_json.pl index 441e7cd5..8b6d73bc 100644 --- a/src/tests/json/test_json.pl +++ b/src/tests/json/test_json.pl @@ -3,11 +3,11 @@ :- use_module(library(charsio)). :- use_module(library(dcgs)). :- use_module(library(format)). -:- use_module(library(json)). +:- use_module(library(iso_ext)). :- use_module(library(lists)). :- use_module(library(os)). :- use_module(library(pio)). -:- use_module(library(iso_ext)). +:- use_module(library(serialization/json)). :- use_module(library(time)). test_path(TestName, TestPath) :- From baed12f45e8133ee7dde14a76b3d9dbbe1251319 Mon Sep 17 00:00:00 2001 From: panasenco Date: Wed, 28 Apr 2021 22:58:04 -0700 Subject: [PATCH 5/5] Oops, we want to keep digits as characters in library(abnf), but as numbers in library(json). --- src/lib/serialization/abnf.pl | 46 ++++++++++++------------- src/lib/serialization/json.pl | 30 ++++++++++++---- src/tests/json/pass_everything.min.json | 2 +- 3 files changed, 47 insertions(+), 31 deletions(-) diff --git a/src/lib/serialization/abnf.pl b/src/lib/serialization/abnf.pl index 40e5d9f6..bf71ab9c 100644 --- a/src/lib/serialization/abnf.pl +++ b/src/lib/serialization/abnf.pl @@ -116,37 +116,37 @@ abnf_alpha('X') --> "X". abnf_alpha('Y') --> "Y". abnf_alpha('Z') --> "Z". -abnf_bit(0) --> "0". -abnf_bit(1) --> "1". +abnf_bit('0') --> "0". +abnf_bit('1') --> "1". -abnf_char(C) --> [C], { dif(C, '\x0000\'), char_type(C, ascii) }. %' +abnf_char(Char) --> [Char], { dif(Char, '\x0000\'), char_type(Char, ascii) }. %' abnf_cr --> "\r". abnf_crlf --> "\r\n". -abnf_ctl(C) --> [C], { char_type(C, ascii), char_type(C, control) }. +abnf_ctl(Char) --> [Char], { char_type(Char, ascii), char_type(Char, control) }. -abnf_digit(0) --> "0". -abnf_digit(1) --> "1". -abnf_digit(2) --> "2". -abnf_digit(3) --> "3". -abnf_digit(4) --> "4". -abnf_digit(5) --> "5". -abnf_digit(6) --> "6". -abnf_digit(7) --> "7". -abnf_digit(8) --> "8". -abnf_digit(9) --> "9". +abnf_digit('0') --> "0". +abnf_digit('1') --> "1". +abnf_digit('2') --> "2". +abnf_digit('3') --> "3". +abnf_digit('4') --> "4". +abnf_digit('5') --> "5". +abnf_digit('6') --> "6". +abnf_digit('7') --> "7". +abnf_digit('8') --> "8". +abnf_digit('9') --> "9". abnf_dquote --> "\"". -abnf_hexdig(Digit) --> abnf_digit(Digit). -abnf_hexdig(10) --> "A". -abnf_hexdig(11) --> "B". -abnf_hexdig(12) --> "C". -abnf_hexdig(13) --> "D". -abnf_hexdig(14) --> "E". -abnf_hexdig(15) --> "F". +abnf_hexdig(Char) --> abnf_digit(Char). +abnf_hexdig('A') --> "A". +abnf_hexdig('B') --> "B". +abnf_hexdig('C') --> "C". +abnf_hexdig('D') --> "D". +abnf_hexdig('E') --> "E". +abnf_hexdig('F') --> "F". abnf_htab --> "\t". @@ -156,11 +156,11 @@ abnf_lwsp --> "". abnf_lwsp --> abnf_wsp, abnf_lwsp. abnf_lwsp --> abnf_clrf, abnf_wsp, abnf_lwsp. -abnf_octet(C) --> [C], char_type(C, octet). +abnf_octet(Char) --> [Char], char_type(Char, octet). abnf_sp --> " ". -abnf_vchar(C) --> [C], char_type(C, ascii_graphic). +abnf_vchar(Char) --> [Char], char_type(Char, ascii_graphic). abnf_wsp --> abnf_sp. abnf_wsp --> abnf_htab. diff --git a/src/lib/serialization/json.pl b/src/lib/serialization/json.pl index 50672e1f..e1bebe11 100644 --- a/src/lib/serialization/json.pl +++ b/src/lib/serialization/json.pl @@ -1,7 +1,7 @@ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Written Apr 2021 by Aram Panasenco (panasenco@ucla.edu) Part of Scryer Prolog. - + `json_chars//1` can be used with [`phrase_from_file/2`](src/lib/pio.pl) or [`phrase/2`](src/lib/dcgs.pl) to parse and generate [JSON](https://www.json.org/json-en.html). @@ -43,7 +43,6 @@ :- use_module(library(dcgs)). :- use_module(library(dif)). :- use_module(library(lists)). -:- use_module(library(serialization/abnf)). /* The DCGs are written to match the McKeeman form presented on the right side of https://www.json.org/json-en.html as closely as possible. Note that the names in the McKeeman form conflict with the pictures on the site. */ @@ -165,13 +164,19 @@ json_character(EscapeChar) --> H4 is (EscapeCharCode // 16^0) mod 16 ) }. -json_hex(Hex) --> abnf_hexdig(Hex). +json_hex(Digit) --> json_digit(Digit). json_hex(10) --> "a". json_hex(11) --> "b". json_hex(12) --> "c". json_hex(13) --> "d". json_hex(14) --> "e". json_hex(15) --> "f". +json_hex(10) --> "A". +json_hex(11) --> "B". +json_hex(12) --> "C". +json_hex(13) --> "D". +json_hex(14) --> "E". +json_hex(15) --> "F". /* I can't think of any alternatives to using `number_chars/2` when generating, though this leads to under-reporting of correct solutions. At least matching solutions unify when both are instantiated... @@ -203,20 +208,31 @@ json_number(Number) --> NumberChars ). -json_integer(Digit) --> abnf_digit(Digit). +json_integer(Digit) --> json_digit(Digit). json_integer(TotalValue) --> json_onenine(FirstDigit), json_digits(RemainingValue, Power), { TotalValue is FirstDigit * 10 ^ (Power + 1) + RemainingValue }. -json_digits(Digit, 0) --> abnf_digit(Digit). +json_digits(Digit, 0) --> json_digit(Digit). json_digits(Value, Power) --> - abnf_digit(FirstDigit), + json_digit(FirstDigit), json_digits(RemainingValue, NextPower), { Power is NextPower + 1, Value is FirstDigit * 10^Power + RemainingValue }. -json_onenine(Digit) --> abnf_digit(Digit), { dif(Digit, 0) }. +json_digit(0) --> "0". +json_digit(Digit) --> json_onenine(Digit). + +json_onenine(1) --> "1". +json_onenine(2) --> "2". +json_onenine(3) --> "3". +json_onenine(4) --> "4". +json_onenine(5) --> "5". +json_onenine(6) --> "6". +json_onenine(7) --> "7". +json_onenine(8) --> "8". +json_onenine(9) --> "9". json_fraction(0) --> "". json_fraction(Fraction) --> diff --git a/src/tests/json/pass_everything.min.json b/src/tests/json/pass_everything.min.json index 5d5659ea..27f37e62 100644 --- a/src/tests/json/pass_everything.min.json +++ b/src/tests/json/pass_everything.min.json @@ -1 +1 @@ -["JSON Test Pattern pass1",{"object with 1 member":["array with 1 element"]},{},[],-42,true,false,null,{"integer":1234567890,"real":-9876.54321,"e":0.000000000000123456789,"E":12345678900000000000000000000000000.0,"":23456789012000000000000000000000000000000000000000000000000000000000000000000,"zero":0,"one":1,"space":" ","quote":"\"","backslash":"\\","controls":"\b\f\n\r\t","slash":"\/ & \/","alpha":"abcdefghijklmnopqrstuvwyz","ALPHA":"ABCDEFGHIJKLMNOPQRSTUVWYZ","digit":"0123456789","special":"`1~!@#$%^&*()_+-={':[,]}|;.<\/>?","hex":"ģ䕧覫\u0001췯ꯍ\u001A","true":true,"false":false,"null":null,"array":[],"object":{},"address":"50 St. James Street","url":"http:\/\/www.JSON.org\/","comment":"\/\/ \/* *\/":" "," s p a c e d ":[1,2,3,4,5,6,7],"compact":[1,2,3,4,5,6,7],"jsontext":"{\"object with 1 member\":[\"array with 1 element\"]}","quotes":"" \" %22 0x22 034 "","\/\\\"쫾몾ꮘﳞ볚\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',.\/<>?":"A key can be any string"},0.5,98.6,99.44,1066,"rosebud"] +["JSON Test Pattern pass1",{"object with 1 member":["array with 1 element"]},{},[],-42,true,false,null,{"integer":1234567890,"real":-9876.54321,"e":0.000000000000123456789,"E":12345678900000000000000000000000000.0,"":23456789012000000000000000000000000000000000000000000000000000000000000000000,"zero":0,"one":1,"space":" ","quote":"\"","backslash":"\\","controls":"\b\f\n\r\t","slash":"\/ & \/","alpha":"abcdefghijklmnopqrstuvwyz","ALPHA":"ABCDEFGHIJKLMNOPQRSTUVWYZ","digit":"0123456789","special":"`1~!@#$%^&*()_+-={':[,]}|;.<\/>?","hex":"ģ䕧覫\u0001췯ꯍ\u001a","true":true,"false":false,"null":null,"array":[],"object":{},"address":"50 St. James Street","url":"http:\/\/www.JSON.org\/","comment":"\/\/ \/* *\/":" "," s p a c e d ":[1,2,3,4,5,6,7],"compact":[1,2,3,4,5,6,7],"jsontext":"{\"object with 1 member\":[\"array with 1 element\"]}","quotes":"" \" %22 0x22 034 "","\/\\\"쫾몾ꮘﳞ볚\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',.\/<>?":"A key can be any string"},0.5,98.6,99.44,1066,"rosebud"]