| 1 | :- use_module(library(error)). | |
| 2 | :- use_module(library(dcg/basics)). |
| 3 | | |
| 4 | :- op(950, xfx, will_be). |
| 5 | | |
| 6 | %%% Basic definitions |
| 7 | | |
| 8 | % apply check to value when bound |
| 9 | will_be(Value, Goal) :- |
| 10 | freeze(Value, assertion(call(Goal, Value))). |
| 11 | | |
| 12 | byte(Value) :- must_be(between(0, 255), Value). |
| 13 | | |
| 14 | nonnegative_integer(Value) :- must_be(nonneg, Value). |
| 15 | | |
| 16 | sequence_of_bytes([]). |
| 17 | sequence_of_bytes([First|Rest]) :- |
| 18 | First will_be byte, |
| 19 | Rest will_be sequence_of_bytes. |
| 20 | | |
| 21 | netstring_encoding(PayloadBytes) --> | Netstring is a sequence of bytes. |
| 22 | netstring_prefix_for_payload(PayloadBytes), | It consists of prefix, |
| 23 | PayloadBytes, | payload, |
| 24 | `,`. | and terminator. Terminator is single ASCII comma `,`. |
| 25 | netstring_encoding(netstring(PayloadBytes), Bytes) :- |
| 26 | assertion(ground(PayloadBytes); ground(Bytes)), |
| 27 | Bytes will_be sequence_of_bytes, |
| 28 | phrase(netstring_encoding(PayloadBytes), Bytes). |
| 29 | | |
| 30 | | Netstring prefix is the shortest ASCII decimal representation for length of
payload in bytes, followed by ASCII colon `:`.
That is number starting with non-zero digit unless payload is empty,
in which case it's `0`. |
| 31 | |
| 32 | |
| 33 | |
| 34 | netstring_prefix_for_payload(PayloadBytes, A, B) :- |
| 35 | ( var(PayloadBytes) |
| 36 | -> netstring_prefix_codes(Prefix, A, B), |
| 37 | number_codes(PayloadLength, Prefix), |
| 38 | length(PayloadBytes, PayloadLength) |
| 39 | ; length(PayloadBytes, PayloadLength), |
| 40 | number_codes(PayloadLength, Prefix), |
| 41 | netstring_prefix_codes(Prefix, A, B) |
| 42 | ). |
| 43 | netstring_prefix_codes(`0`) --> `0:`, !. |
| 44 | netstring_prefix_codes([C|Cs]) --> |
| 45 | nonzero_digit(C), |
| 46 | !, |
| 47 | digits(Cs), |
| 48 | `:`. |
| 49 | | |
| 50 | nonzero_digit(Code) --> |
| 51 | [Code], |
| 52 | { assertion(ground(Code)) }, |
| 53 | { member(Code, `123456789`) }. |
| 54 | | |
| 55 | netstring_of(Goal, Bytes) :- |
| 56 | ground(Goal), |
| 57 | !, |
| 58 | call(Goal, PayloadBytes), |
| 59 | netstring_encoding(netstring(PayloadBytes), Bytes). |
| 60 | | |
| 61 | netstring_of(Goal, Bytes) :- |
| 62 | ground(Bytes), |
| 63 | !, |
| 64 | netstring_encoding(netstring(PayloadBytes), Bytes), |
| 65 | call(Goal, PayloadBytes). |
| 66 | | |
| 67 | | |
| 68 | % :- use_module(library(pldoc/doc_files)). |
| 69 | % doc_save('spec.pl', [format(html), doc_root(.)]). |