From 20f192daa14473c0428bf95d07aa24dc680c71a4 Mon Sep 17 00:00:00 2001 From: panasenco Date: Sun, 18 Apr 2021 23:44:10 -0700 Subject: [PATCH] Changed formatting to match Markus Triska's as much as I can tell --- src/lib/json.pl | 220 ++++++++++++++++++++++-------------------------- 1 file changed, 100 insertions(+), 120 deletions(-) diff --git a/src/lib/json.pl b/src/lib/json.pl index 1875d3c7..959f6b45 100644 --- a/src/lib/json.pl +++ b/src/lib/json.pl @@ -47,7 +47,7 @@ :- use_module(library(lists)). :- use_module(library(reif)). -/* The DCGs are written to match the McKeeman Form presented on the right side of https://www.json.org/json-en.html +/* The DCGs are written to match the McKeeman form presented on the right side of https://www.json.org/json-en.html almost perfectly. Note that the McKeeman form conflicts some with the pictures on the left side. */ json_chars(Internal) --> json_element(Internal). @@ -55,13 +55,13 @@ 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 Down the line we'll incorporate more JSON Schema support, but this is it for now. */ -json_value(object(Assoc)) --> json_object(Assoc). -json_value(array(List)) --> json_array(List). -json_value(string(Chars)) --> json_string(Chars). -json_value(number(Number)) --> json_number(Number). -json_value(boolean(true)) --> "true". -json_value(boolean(false)) --> "false". -json_value(null) --> "null". +json_value(object(Assoc)) --> json_object(Assoc). +json_value(array(List)) --> json_array(List). +json_value(string(Chars)) --> json_string(Chars). +json_value(number(Number)) --> json_number(Number). +json_value(boolean(true)) --> "true". +json_value(boolean(false)) --> "false". +json_value(null) --> "null". /* Read Bob Kowalski's "Algorithm = Logic + Control": https://www.doc.ic.ac.uk/~rak/papers/algorithm%20=%20logic%20+%20control.pdf @@ -73,38 +73,36 @@ json_value(null) --> "null". Maybe at some point in the future we'll have a library that takes a pure logic character parsing/generating DCG and 'injects' control strategy into it. We aren't there yet... */ json_object(EmptyAssoc) --> {empty_assoc(EmptyAssoc)}, "{", json_ws, "}". -json_object(Assoc) --> - { - nonvar(Assoc) -> - \+ empty_assoc(Assoc), - assoc_to_list(Assoc, [Pair|Pairs]) - ; true - }, - "{", - json_members([Pair|Pairs]), - "}", - { - var(Assoc) -> - list_to_assoc([Pair|Pairs], Assoc) - ; true - }. - -json_members([Key-Value]) --> json_member(Key, Value). +json_object(Assoc) --> + { ( nonvar(Assoc) -> + \+ empty_assoc(Assoc), + assoc_to_list(Assoc, [Pair|Pairs]) + ; true + ) }, + "{", + json_members([Pair|Pairs]), + "}", + { ( var(Assoc) -> + list_to_assoc([Pair|Pairs], Assoc) + ; true + ) }. + +json_members([Key-Value]) --> json_member(Key, Value). json_members([Key-Value | Pairs]) --> json_member(Key, Value), ",", json_members(Pairs). json_member(Key, Value) --> json_ws, json_string(Key), json_ws, ":", json_element(Value). -json_array([]) --> "[", json_ws, "]". +json_array([]) --> "[", json_ws, "]". json_array([Value|Values]) --> "[", json_elements([Value|Values]), "]". -json_elements([Value]) --> json_element(Value). +json_elements([Value]) --> json_element(Value). json_elements([Value|Values]) --> json_element(Value), ",", json_elements(Values). json_element(Value) --> json_ws, json_value(Value), json_ws. json_string(Chars) --> "\"", json_characters(Chars), "\"". -json_characters("") --> "". +json_characters("") --> "". json_characters([Char|Chars]) --> json_character(Char), json_characters(Chars). /* A directly printable character is defined by the JSON spec as a character between 0020 and 10FFFF except the @@ -114,114 +112,100 @@ json_characters([Char|Chars]) --> json_character(Char), json_characters(Chars). If we moved the block containing `char_code/2` up before `[PrintChar]`, we would still be able to generate JSON, but attempting to parse JSON would cause an instantiation error. */ escape_map([ - '"' - '"', - ('\\') - ('\\'), - ('/') - ('/'), - '\b' - 'b', - '\f' - 'f', - '\n' - 'n', - '\r' - 'r', - '\t' - 't' -]). - -json_character(PrintChar) --> - [PrintChar], - { - escape_map(EscapeMap), - \+ member(PrintChar-_, EscapeMap), - char_code(PrintChar, PrintCharCode), - PrintCharCode in 32..1114111 /* 20.10FFFF */ - }. + '"' - '"', + ('\\') - ('\\'), + ('/') - ('/'), + '\b' - 'b', + '\f' - 'f', + '\n' - 'n', + '\r' - 'r', + '\t' - 't' ]). + +json_character(PrintChar) --> + [PrintChar], + { escape_map(EscapeMap), + \+ member(PrintChar-_, EscapeMap), + char_code(PrintChar, PrintCharCode), + PrintCharCode in 32..1114111 /* 20.10FFFF */ }. json_character(EscapeChar) --> "\\", json_escape(EscapeChar). json_escape(EscapeChar) --> - [PrintChar], - { - escape_map(EscapeMap), - member(EscapeChar-PrintChar, EscapeMap) - }. + [PrintChar], + { escape_map(EscapeMap), + member(EscapeChar-PrintChar, EscapeMap) }. json_escape(EscapeChar) --> - "u", - { /* Logic: Define the domain of the escape character as well as the relationship between the escape character + "u", + /* Logic: Define the domain of the escape character as well as the relationship between the escape character and the four hexes */ - [H1, H2, H3, H4] ins 0..15, - EscapeCharCode in 0..65535, - EscapeCharCode #= H1 * 16^3 + H2 * 16^2 + H3 * 16 + H4 - }, - { /* Control: Get the code of the escape character if we can. Otherwise we'll end up backtracking over 65,536 - possible hex values. - Logic: Only the first 32 Unicode characters not escaped in the escape map are eligible for \u-escaping - when generating. However, we want to be able to parse any of the 65,536 \u-escaped values when parsing. */ - nonvar(EscapeChar) -> - char_code(EscapeChar, EscapeCharCode), - EscapeCharCode in 0..31, - escape_map(EscapeMap), - \+ member(EscapeChar-_, EscapeMap) - ; true - }, - json_hex(H1), - json_hex(H2), - json_hex(H3), - json_hex(H4), - { /* Control + Logic: Get the escape character atom from the character code computed from the hexes. */ - var(EscapeChar) -> - char_code(EscapeChar, EscapeCharCode) - ; true - }. + { [H1, H2, H3, H4] ins 0..15, + EscapeCharCode in 0..65535, + EscapeCharCode #= H1 * 16^3 + H2 * 16^2 + H3 * 16 + H4, + /* Control: Get the code of the escape character if we can. Otherwise we'll end up backtracking over 65,536 + possible hex values. + Logic: Only the first 32 Unicode characters not escaped in the escape map are eligible for \u-escaping + when generating. However, we want to be able to parse any of the 65,536 \u-escaped values when parsing. */ + ( nonvar(EscapeChar) -> + char_code(EscapeChar, EscapeCharCode), + EscapeCharCode in 0..31, + escape_map(EscapeMap), + \+ member(EscapeChar-_, EscapeMap) + ; true + ) + }, + json_hex(H1), + json_hex(H2), + json_hex(H3), + json_hex(H4), + /* Control + Logic: Get the escape character atom from the character code computed from the hexes. */ + { ( var(EscapeChar) -> + char_code(EscapeChar, EscapeCharCode) + ; true + ) }. 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". +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". /* Here we are going to write completely different DCGs for parsing and generating, and rely on built-in predicates. However, the underlying logic remains the same. */ json_number(Number) --> - { - nonvar(Number) -> - number_chars(Number, NumberChars) - ; false - }, + { ( nonvar(Number) -> + number_chars(Number, NumberChars) + ; false + ) }, NumberChars. json_number(Number) --> - { - var(Number) - }, + { var(Number) }, json_sign_noplus(Sign), json_integer(Integer), json_fraction(Fraction), json_exponent(Exponent), - { - Number is Sign * (Integer + Fraction) * 10.0 ^ Exponent - }. + { Number is Sign * (Integer + Fraction) * 10.0 ^ Exponent }. -json_integer(Digit) --> json_digit(Digit). +json_integer(Digit) --> json_digit(Digit). json_integer(TotalValue) --> json_onenine(FirstDigit), json_digits(RemainingValue, Power), - { - TotalValue #= FirstDigit * 10 ^ (Power + 1) + RemainingValue - }. + { TotalValue #= FirstDigit * 10 ^ (Power + 1) + RemainingValue }. -json_digits(Digit, 0) --> json_digit(Digit). +json_digits(Digit, 0) --> json_digit(Digit). json_digits(Value, Power) --> json_digit(FirstDigit), json_digits(RemainingValue, NextPower), - { - Power #= NextPower + 1, - Value #= FirstDigit * 10^Power + RemainingValue - }. + { Power #= NextPower + 1, + Value #= FirstDigit * 10^Power + RemainingValue }. -json_digit(0) --> "0". +json_digit(0) --> "0". json_digit(Digit) --> json_onenine(Digit). json_onenine(1) --> "1". @@ -234,31 +218,27 @@ json_onenine(7) --> "7". json_onenine(8) --> "8". json_onenine(9) --> "9". -json_fraction(0) --> "". +json_fraction(0) --> "". json_fraction(Fraction) --> ".", json_digits(Value, Power), - { - Fraction is Value / 10 ^ (Power + 1) - }. + { Fraction is Value / 10 ^ (Power + 1) }. -json_exponent(0) --> "". +json_exponent(0) --> "". json_exponent(Exponent) --> json_exponent_signifier, json_sign(Sign), json_digits(Value, _), - { - Exponent #= Sign * Value - }. + { Exponent #= Sign * Value }. json_exponent_signifier --> "E". json_exponent_signifier --> "e". -json_sign_noplus(1) --> "". +json_sign_noplus(1) --> "". json_sign_noplus(-1) --> "-". json_sign(Sign) --> json_sign_noplus(Sign). -json_sign(1) --> "+". +json_sign(1) --> "+". json_ws --> "". json_ws --> " ", json_ws. -- 2.54.0