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(.)]). |