commit 0115452a17b566c5810acfeb4bb16e0a353048f9
parent df11fb12eae38d88b7a219399a4fc5c1d81cf67a
Author: Jan Pobrislo <ccx@te2000.cz>
Date: Thu, 24 Apr 2025 23:10:16 +0000
awk script for generating html of specification
Diffstat:
4 files changed, 136 insertions(+), 19 deletions(-)
diff --git a/doc/Makefile b/doc/Makefile
@@ -0,0 +1,3 @@
+spec.html: spec.pl spec2html.awk
+ awk -f spec2html.awk spec.pl >'$@.new'
+ mv '$@.new' '$@'
diff --git a/doc/spec.html b/doc/spec.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html><body><table>
+<tr><td>1</td><td><pre>:- use_module(library(error)).</pre></td><td rowspan="2"></td></tr>
+<tr><td>2</td><td><pre>:- use_module(library(dcg/basics)).</pre></td></tr>
+<tr><td>3</td><td><pre></pre></td><td rowspan="2"></td></tr>
+<tr><td>4</td><td><pre>:- op(950, xfx, will_be).</pre></td></tr>
+<tr><td>5</td><td><pre></pre></td><td rowspan="2"></td></tr>
+<tr><td>6</td><td><pre>%%% Basic definitions</pre></td></tr>
+<tr><td>7</td><td><pre></pre></td><td rowspan="4"></td></tr>
+<tr><td>8</td><td><pre>% apply check to value when bound</pre></td></tr>
+<tr><td>9</td><td><pre>will_be(Value, Goal) :-</pre></td></tr>
+<tr><td>10</td><td><pre> freeze(Value, call(Goal, Value)).</pre></td></tr>
+<tr><td>11</td><td><pre></pre></td><td rowspan="2"></td></tr>
+<tr><td>12</td><td><pre>byte(Value) :- must_be(between(0, 255), Value).</pre></td></tr>
+<tr><td>13</td><td><pre></pre></td><td rowspan="2"></td></tr>
+<tr><td>14</td><td><pre>nonnegative_integer(Value) :- must_be(nonneg, Value).</pre></td></tr>
+<tr><td>15</td><td><pre></pre></td><td rowspan="5"></td></tr>
+<tr><td>16</td><td><pre>sequence_of_bytes([]).</pre></td></tr>
+<tr><td>17</td><td><pre>sequence_of_bytes([First|Rest]) :-</pre></td></tr>
+<tr><td>18</td><td><pre> First will_be byte,</pre></td></tr>
+<tr><td>19</td><td><pre> Rest will_be sequence_of_bytes.</pre></td></tr>
+<tr><td>20</td><td><pre></pre></td><td rowspan="1"></td></tr>
+<tr><td>21</td><td><pre>netstring_encoding(PayloadLength, PayloadBytes) -->gt; %<lt; Netstring is a sequence of bytes.</pre></td><td rowspan="2"></td></tr>
+<tr><td>22</td><td><pre> { length(PayloadBytes, PayloadLength) },</pre></td></tr>
+<tr><td>23</td><td><pre> netstring_prefix(PayloadLength), %<lt; It consists of prefix,</pre></td><td rowspan="1"></td></tr>
+<tr><td>24</td><td><pre> PayloadBytes, %<lt; payload,</pre></td><td rowspan="1"></td></tr>
+<tr><td>25</td><td><pre> `,`. %<lt; and terminator. Terminator is single ASCII comma `,`.</pre></td><td rowspan="5"></td></tr>
+<tr><td>26</td><td><pre>netstring_encoding(netstring(PayloadLength, PayloadBytes), Bytes) :-</pre></td></tr>
+<tr><td>27</td><td><pre> Bytes will_be sequence_of_bytes,</pre></td></tr>
+<tr><td>28</td><td><pre> PayloadLength will_be nonnegative_integer,</pre></td></tr>
+<tr><td>29</td><td><pre> phrase(netstring_encoding(PayloadLength, PayloadBytes), Bytes).</pre></td></tr>
+<tr><td>30</td><td><pre></pre></td><td rowspan="4">
+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`.</td></tr>
+<tr><td>31</td><td><pre></pre></td></tr>
+<tr><td>32</td><td><pre>netstring_prefix(0) -->gt; `0:`.</pre></td></tr>
+<tr><td>33</td><td><pre>netstring_prefix(N) -->gt; positive_decimal(N), `:`.</pre></td></tr>
+<tr><td>34</td><td><pre></pre></td><td rowspan="7"></td></tr>
+<tr><td>35</td><td><pre>positive_decimal(N) -->gt;</pre></td></tr>
+<tr><td>36</td><td><pre> { freeze(N, format(codes([C|Cs]), '~w', N)) },</pre></td></tr>
+<tr><td>37</td><td><pre> nonzero_digit(C),</pre></td></tr>
+<tr><td>38</td><td><pre> digits(Cs),</pre></td></tr>
+<tr><td>39</td><td><pre> { phrase(number(N), [C|Cs]) }.</pre></td></tr>
+<tr><td>40</td><td><pre>nonzero_digit(Code) -->gt; [Code], {member(Code, `123456789`)}.</pre></td></tr>
+<tr><td>41</td><td><pre></pre></td><td rowspan="6"></td></tr>
+<tr><td>42</td><td><pre>netstring_of(Goal, Bytes) :-</pre></td></tr>
+<tr><td>43</td><td><pre> ground(Goal),</pre></td></tr>
+<tr><td>44</td><td><pre> !,</pre></td></tr>
+<tr><td>45</td><td><pre> call(Goal, PayloadBytes),</pre></td></tr>
+<tr><td>46</td><td><pre> netstring_encoding(netstring(_, PayloadBytes), Bytes).</pre></td></tr>
+<tr><td>47</td><td><pre></pre></td><td rowspan="6"></td></tr>
+<tr><td>48</td><td><pre>netstring_of(Goal, Bytes) :-</pre></td></tr>
+<tr><td>49</td><td><pre> ground(Bytes),</pre></td></tr>
+<tr><td>50</td><td><pre> !,</pre></td></tr>
+<tr><td>51</td><td><pre> netstring_encoding(netstring(_, PayloadBytes), Bytes),</pre></td></tr>
+<tr><td>52</td><td><pre> call(Goal, PayloadBytes).</pre></td></tr>
+<tr><td>53</td><td><pre></pre></td><td rowspan="1"></td></tr>
+<tr><td>54</td><td><pre></pre></td><td rowspan="3"></td></tr>
+<tr><td>55</td><td><pre>% :- use_module(library(pldoc/doc_files)).</pre></td></tr>
+<tr><td>56</td><td><pre>% doc_save('spec.pl', [format(html), doc_root(.)]).</pre></td></tr>
+</table></body></html>
diff --git a/doc/spec.pl b/doc/spec.pl
@@ -1,13 +1,15 @@
:- use_module(library(error)).
-:- use_module(library(http/dcg_basics)).
+:- use_module(library(dcg/basics)).
:- op(950, xfx, will_be).
-will_be(Value, Predicate) :-
- freeze(Value, call(Predicate, Value)).
+%%% Basic definitions
+
+% apply check to value when bound
+will_be(Value, Goal) :-
+ freeze(Value, call(Goal, Value)).
byte(Value) :- must_be(between(0, 255), Value).
-% integer(Value), Value >= 0, Value <= 255.
nonnegative_integer(Value) :- must_be(nonneg, Value).
@@ -15,30 +17,27 @@ sequence_of_bytes([]).
sequence_of_bytes([First|Rest]) :-
First will_be byte,
Rest will_be sequence_of_bytes.
-% freeze(First, byte(First)),
-% freeze(Rest, sequence_of_bytes(Rest)).
+netstring_encoding(PayloadLength, PayloadBytes) --> %< Netstring is a sequence of bytes.
+ { length(PayloadBytes, PayloadLength) },
+ netstring_prefix(PayloadLength), %< It consists of prefix,
+ PayloadBytes, %< payload,
+ `,`. %< and terminator. Terminator is single ASCII comma `,`.
netstring_encoding(netstring(PayloadLength, PayloadBytes), Bytes) :-
Bytes will_be sequence_of_bytes,
PayloadLength will_be nonnegative_integer,
- % freeze(Bytes, sequence_of_bytes(Bytes)),
- % freeze(PayloadLength, integer(PayloadLength)).
phrase(netstring_encoding(PayloadLength, PayloadBytes), Bytes).
-%length(Payload, PayloadLength),
-netstring_encoding(PayloadLength, PayloadBytes) -->
- {length(PayloadBytes, PayloadLength)},
- netstring_prefix(PayloadLength),
- PayloadBytes,
- `,`.
-nonzero_digit(Code) --> [Code], {member(Code, `123456789`)}.
+%> 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`.
+netstring_prefix(0) --> `0:`.
+netstring_prefix(N) --> positive_decimal(N), `:`.
+
positive_decimal(N) -->
- {freeze(N, format(codes([C|Cs]), '~w', N))},
+ { freeze(N, format(codes([C|Cs]), '~w', N)) },
nonzero_digit(C),
digits(Cs),
- {phrase(number(N), [C|Cs])}.
-netstring_prefix(0) --> `0:`.
-netstring_prefix(N) --> positive_decimal(N), `:`.
+ { phrase(number(N), [C|Cs]) }.
+nonzero_digit(Code) --> [Code], {member(Code, `123456789`)}.
netstring_of(Goal, Bytes) :-
ground(Goal),
@@ -52,5 +51,6 @@ netstring_of(Goal, Bytes) :-
netstring_encoding(netstring(_, PayloadBytes), Bytes),
call(Goal, PayloadBytes).
+
% :- use_module(library(pldoc/doc_files)).
% doc_save('spec.pl', [format(html), doc_root(.)]).
diff --git a/doc/spec2html.awk b/doc/spec2html.awk
@@ -0,0 +1,54 @@
+#!/usr/bin/awk -f
+
+BEGIN {
+ FS="%[>^] "
+ printf("%s\n", "<!DOCTYPE html>")
+ printf("%s\n", "<html><body><table>")
+ last_comm = 1
+}
+
+/%< / || /^$/{
+ last_comm = NR
+}
+
+{
+ code[NR] = $1
+ if(last_comm in comm) {
+ if(length($2)) {
+ comm[last_comm] = comm[last_comm] "\n" $2
+ }
+ } else {
+ comm[last_comm] = $2
+ }
+ span[last_comm] = span[last_comm] + 1
+}
+
+function entity_escape(s) {
+ gsub(/&/, "&", s)
+ gsub(/</, "<", s)
+ gsub(/>/, ">", s)
+ return s
+}
+
+function line(n){
+ if(span[n]) {
+ printf("<tr><td>%d</td><td><pre>%s</pre></td><td rowspan=\"%d\">%s</td></tr>\n"\
+ , n \
+ , entity_escape(code[n]) \
+ , span[n] \
+ , entity_escape(comm[n]) \
+ )
+ } else {
+ printf("<tr><td>%d</td><td><pre>%s</pre></td></tr>\n"\
+ , n \
+ , entity_escape(code[n]) \
+ )
+ }
+}
+
+END {
+ for(n=1; (n in code); n++) {
+ line(n)
+ }
+ printf("%s\n", "</table></body></html>");
+}