Fil-C on Nix

Filnix wiki

the formal campaign

rocq/backend/IrText.v

A reader of IR text (src/ir_text.pl): a module written as Prolog clauses, one func/5, data/4, alias/3 or context/2 term per item, which the Prolog compiler reads with read_term/3. This reader gives the same term as read_ir_file/3 or gives nothing: it never reads a text differently from SWI-Prolog.

It reads what the printer of ir_text.pl writes and a little more: % and block comments, names, quoted atoms and double-quoted strings with their escapes, symbol atoms, decimal integers, compounds, proper lists, and one operator, an infix - between two terms (a phi's edges are written start-const(0)). It gives nothing for the rest of Prolog's syntax: variables, every other use of an operator, parentheses around a term, a bar in a list, floats, the other number forms, back-quoted strings, and any byte outside ASCII that is not inside quotes.

A term becomes a term as the backend's driver reads the terms Prolog prints: [ ] is TList[ ], the quoted atom '[]' is TAtom"[]", an atom's name is its UTF-8 bytes, and a double-quoted string is the list of its characters, each an atom of one character.

The text is the list of the file's bytes. Every loop over the text, the clauses, the arguments of a compound and the elements of a list is a tail call, so the extracted reader needs no more stack for 200,000 items than for one; the terms being read are kept in a list of frames, not in the calls.

From Stdlib Require Import String ZArith List Bool Ascii Arith
From Nanofil Require Import Term
Import ListNotations

Characters

The three definitions below are the ones to give an OCaml definition of when extracting: taking a character apart into its eight bits is slow there.

The code of the character c, 0 to 255.

40Definition codec : ascii : nat ≔
nat_of_asciic

The character whose code is n, for an n below 256.

43Definition byten : nat : ascii ≔
ascii_of_natn

The string of the characters cs, which are given last first, as a loop collects them.

47Definition string_of_revcs : listascii : string ≔
string_of_list_asciirev_appendcs [ ]

The codes of the characters the reader names.

50Definition c_tab: nat ≔
9
51Definition c_nl: nat ≔
10
52Definition c_cr: nat ≔
13
53Definition c_space: nat ≔
32
54Definition c_bang: nat ≔
33
55Definition c_dquote: nat ≔
34
56Definition c_percent: nat ≔
37
57Definition c_squote: nat ≔
39
58Definition c_lparen: nat ≔
40
59Definition c_rparen: nat ≔
41
60Definition c_star: nat ≔
42
61Definition c_comma: nat ≔
44
62Definition c_minus: nat ≔
45
63Definition c_dot: nat ≔
46
64Definition c_slash: nat ≔
47
65Definition c_0: nat ≔
48
66Definition c_9: nat ≔
57
67Definition c_semicolon: nat ≔
59
68Definition c_upper_a: nat ≔
65
69Definition c_upper_z: nat ≔
90
70Definition c_lbracket: nat ≔
91
71Definition c_backslash: nat ≔
92
72Definition c_rbracket: nat ≔
93
73Definition c_underscore: nat ≔
95
74Definition c_a: nat ≔
97
75Definition c_x: nat ≔
120
76Definition c_z: nat ≔
122
77Definition c_lbrace: nat ≔
123
78Definition c_rbrace: nat ≔
125
79Definition c_tilde: nat ≔
126
80Definition c_7: nat ≔
55
81Definition c_upper_f: nat ≔
70
82Definition c_f: nat ≔
102

Numbers the reader counts with: the two bases of a numeric escape, one more than the most digits of one, what a letter's code is above its value as a digit, and the first bytes and the continuation bytes of UTF-8. Each is a definition of its own because the extracted code builds a number again each time it meets one written inside a function.

90Definition eight: nat ≔
8
91Definition sixteen: nat ≔
16
92Definition nine: nat ≔
9
93Definition upper_digit: nat ≔
55
94Definition lower_digit: nat ≔
87
95Definition b128: nat ≔
128
96Definition b143: nat ≔
143
97Definition b144: nat ≔
144
98Definition b159: nat ≔
159
99Definition b160: nat ≔
160
100Definition b191: nat ≔
191
101Definition b194: nat ≔
194
102Definition b223: nat ≔
223
103Definition b224: nat ≔
224
104Definition b225: nat ≔
225
105Definition b237: nat ≔
237
106Definition b239: nat ≔
239
107Definition b240: nat ≔
240
108Definition b241: nat ≔
241
109Definition b243: nat ≔
243
110Definition b244: nat ≔
244

Whether n is from lo to hi, both included.

113Definition betweenlo hi n : nat : bool ≔
lo ≤? n && n ≤? hi

Whether the code n is layout: a space, a newline, a tab or a carriage return.

117Definition is_layoutn : nat : bool ≔
n =? c_space || n =? c_nl || n =? c_tab || n =? c_cr

Whether the code n is a lowercase letter, which starts a name.

121Definition is_lowern : nat : bool ≔

Whether the code n is a decimal digit.

124Definition is_digitn : nat : bool ≔

Whether the code n may follow the first letter of a name: a letter, a digit or an underscore.

128Definition is_alnumn : nat : bool ≔

The codes of Prolog's symbol characters, #$&*+-/:<=>?@\^~, but for the full stop, which the reader takes only as a clause's end.

134Definition symbol_codes: listnat ≔
35; 36; 38; 42; 43; 45; 47; 58; 60; 61; 62; 63; 64; 92; 94; 126

Whether the code n is a symbol character other than the full stop. A run of them is one atom, as + or =<.

139Definition is_symboln : nat : bool ≔

Whether the code n may stand as itself in a comment or between quotes: a printing ASCII character.

143Definition is_printingn : nat : bool ≔

Whether the text cs starts with the character of code n.

146Definition startsn : nat cs : listascii : bool ≔
match cs with
[ ]
⇒
false
c :: _
⇒
codec =? n

Layout and comments

Where the reader is while it skips layout: between tokens, in a % comment, in a block comment, or in a block comment just after a *.

157Inductive skip_state: Type ≔
|InLayout
|InLine
|InBlock
|InStar

The text cs from its first character that is neither layout nor in a comment, the reader being in the state s. Nothing for a block comment that does not end, for a block comment with a /* inside it (SWI-Prolog nests them), and for a character in a comment that is not ASCII printing or layout. A / that no * follows is not a comment and is left in the text.

Names and integers

The name whose characters after those in acc (last first) are the letters, digits and underscores at the front of cs, and the text after it.

210Fixpoint identcs : listascii acc : listascii : string × listascii ≔
match cs with
[ ]
⇒
c :: cs′
⇒
→
identcs′ c :: acc
else

The symbol atom whose characters after those in acc are the symbol characters at the front of cs, and the text after it. Nothing when the run has a / then a *, which SWI does not read as one atom. The run stops before a full stop, and the step after the atom refuses one there: inside brackets always, and outside them because a lone symbol atom is no item. So =.. is refused, though SWI reads it.

224Fixpoint symbolscs : listascii acc : listascii : optionstring × listascii ≔
match cs with
[ ]
⇒
Somestring_of_revacc, [ ]
c :: cs′
⇒
let n ≔ codec in
→
n =? c_slash && startsc_star cs′
→
None
else
symbolscs′ c :: acc
else
Somestring_of_revacc, cs

Ten, the base of an integer's digits. A definition of its own, so the extracted reader builds the number once.

236Definition ten: Z ≔
10

The integer whose digits are those of z and then the decimal digits at the front of cs, and the text after them.

240Fixpoint digitscs : listascii z : Z : Z × listascii ≔
match cs with
[ ]
⇒
z, [ ]
c :: cs′
⇒
let n ≔ codec in
→
digitscs′ z × ten + Z.of_natn − c_0%Z
else
z, cs

Quoted text

The escapes of one character after a backslash, each with the code it stands for: \a, \b, \f, \n, \r, \t, \v, and a backslash or a quote of any kind standing for itself.

253Definition escapes: listnat × Z ≔
97, 7%Z; 98, 8%Z; 102, 12%Z; 110, 10%Z; 114, 13%Z; 116, 9%Z; 118, 11%Z; 92, 92%Z; 39, 39%Z; 34, 34%Z; 96, 96%Z

The code the escape character of code n stands for in the table l, if it is there.

259Fixpoint escape_coden : nat l : listnat × Z : optionZ ≔
match l with
[ ]
⇒
None
k, z :: l′
⇒
n =? k
→
Somez
else

The value of the character of code n as a digit in the base base, 8 or 16, if it is one. A hexadecimal digit's letter may be of either case.

268Definition digit_valuebase n : nat : optionnat ≔
let d ≔
in
d <? base
→
Somed
else
None

The number whose digits in the base base are those of z and then the digits at the front of cs, which a backslash must end, and the text after that backslash. fuel is one more than the most digits read: nothing for a longer number.

280Fixpoint numericfuel base : nat cs : listascii z : Z : optionZ × listascii ≔
match fuel with
O
⇒
None
Sfuel′
⇒
match cs with
[ ]
⇒
None
c :: cs′
⇒
let n ≔ codec in
→
Somez, cs′
else
match digit_valuebase n with
Somed
⇒
numericfuel′ base cs′ z × Z.of_natbase + Z.of_natd%Z
None
⇒
None

The numbers of UTF-8: where each longer form starts, and what its bytes add to their six bits. Definitions of their own, as ten.

299Definition z64: Z ≔
64
300Definition z128: Z ≔
128
301Definition z192: Z ≔
192
302Definition z224: Z ≔
224
303Definition z240: Z ≔
240
304Definition z2048: Z ≔
2048
305Definition z4096: Z ≔
4096
306Definition z65536: Z ≔
65536
307Definition z262144: Z ≔
262144

The last character code, 0x10FFFF, and the first and the last surrogate, 0xD800 and 0xDFFF, which are no characters.

311Definition last_code: Z ≔
1114111
312Definition first_surrogate: Z ≔
55296
313Definition last_surrogate: Z ≔
57343

Whether z is a character code an escape may give: not above 0x10FFFF, and not a surrogate (0xD800 to 0xDFFF). Zero is one: \0\ is the NUL character.

318Definition is_char_codez : Z : bool ≔
0 ≤? z && z ≤? last_code && negbfirst_surrogate ≤? z && z ≤? last_surrogate%Z

The character whose code is z, for a z from 0 to 255.

322Definition zbytez : Z : ascii ≔
byteZ.to_natz

The UTF-8 bytes of the character code z, last first, in front of acc.

326Definition utf8z : Z acc : listascii : listascii ≔
z <? z128
→
zbytez :: acc
z <? z2048
→
zbytez128 + z mod z64 :: zbytez192 + z / z64 :: acc
z <? z65536
→
zbytez128 + z mod z64 :: zbytez128 + z / z64 mod z64 :: zbytez224 + z / z4096 :: acc
else
zbytez128 + z mod z64 :: zbytez128 + z / z64 mod z64 :: zbytez128 + z / z4096 mod z64 :: zbytez240 + z / z262144 :: acc

The code that the escape at the front of cs stands for, cs being the text after a backslash, and the text after the escape. The escapes are those of escapes, \x with one to eight hexadecimal digits and a closing backslash, and one to eight octal digits with a closing backslash. Nothing for any other escape, and for a number that is not a character's code.

342Definition escapecs : listascii : optionZ × listascii ≔
match cs with
[ ]
⇒
None
c :: cs′
⇒
let n ≔ codec in
match escape_coden escapes with
Somez
⇒
Somez, cs′
None
⇒
match if n =? c_x then if startsc_backslash cs′ then None else numericnine sixteen cs′ 0%Z else if betweenc_0 c_7 n then numericnine eight cs 0%Z else None with
Somez, cs′′
⇒
→
Somez, cs′′
else
None
None
⇒
None

The text cs after k bytes that continue a UTF-8 character, with those bytes in front of acc, last first. The first of them must have a code from lo to hi, the others one from 128 to 191. Nothing when a byte is not such a one.

364Fixpoint continuationk lo hi : nat cs : listascii acc : listascii : optionlistascii × listascii ≔
match k with
O
⇒
Someacc, cs
Sk′
⇒
match cs with
[ ]
⇒
None
c :: cs′
⇒
→
continuationk′ b128 b191 cs′ c :: acc
else
None

The same for a UTF-8 character whose first byte, of code n, is already in acc: the bytes that must follow it are read. Nothing for a first byte that starts no character, and for the forms UTF-8 forbids: a longer form than a code needs, a surrogate, and a code above 0x10FFFF. SWI reads such bytes as other characters than the ones the bytes spell.

382Definition utf8_restn : nat cs : listascii acc : listascii : optionlistascii × listascii ≔

The bytes of a quoted atom or a string, last first and in front of acc, and the text after its closing quote. cs is the text after the opening quote, whose code is q. A doubled quote is one quote, a backslash starts an escape (escape), and a character outside ASCII must be well-formed UTF-8. Nothing for text with no closing quote and for a control character, a newline included, written as itself. fuel is at least the length of cs.

401Fixpoint quotedfuel q : nat cs : listascii acc : listascii : optionlistascii × listascii ≔
match fuel with
O
⇒
None
Sfuel′
⇒
match cs with
[ ]
⇒
None
c :: cs′
⇒
let n ≔ codec in
n =? q
→
startsq cs′
→
quotedfuel′ q tlcs′ c :: acc
else
Someacc, cs′
→
match escapecs′ with
Somez, cs′′
⇒
quotedfuel′ q cs′′ utf8z acc
None
⇒
None
→
quotedfuel′ q cs′ c :: acc
n <? b128
→
None
else
match utf8_restn cs′ c :: acc with
Someacc′, cs′′
⇒
quotedfuel′ q cs′′ acc′
None
⇒
None

The characters of a string in front of acc, each the atom of its UTF-8 bytes. bs is the string's bytes, last first, and tail the bytes already seen of the character being read.

430Fixpoint charsbs : listascii tail : listascii acc : listterm : listterm ≔
match bs with
[ ]
⇒
acc
b :: bs′
⇒
→
charsbs′ b :: tail acc
else
charsbs′ [ ] TAtomstring_of_revrev_appendtail b :: acc

Terms

A term the reader is inside of, with what it has read of it: a compound with its name and the arguments so far, a list with the elements so far (both last first), or an infix - with its left side.

444Inductive frame: Type ≔
|FApp
f : string args : listterm
|FList
elems : listterm
|FMinus
a : term

What the reader expects next. MTermfirst: a term, or, when first holds, the ] of an empty list. MSepv lhs: what may follow the term v just read, which is a comma, a closing bracket, a full stop or, when lhs holds, an infix -.

453Inductive mode: Type ≔
|MTerm
first : bool
|MSep
v : term lhs : bool

What one step of the reader gives: a refusal, the end of the text, a whole clause and the text after its full stop, or the text, the frames and the mode to go on with.

460Inductive step: Type ≔
|Fail
|Done
|Clause
t : term cs : listascii
|Next
cs : listascii st : listframe m : mode

The step after the term v has been read, cs being the text after it and st the frames: as the right side of an infix - it makes that term, after which no second - may come.

469Definition valuev : term lhs : bool cs : listascii st : listframe : step ≔
match st with
FMinusa :: st′
⇒
Nextcs st′ MSepTApp"-" a; v false
_
⇒
Nextcs st MSepv lhs

The step after the name name: a compound's start when a ( follows it at once, else the atom. lhs is whether the atom may be the left side of an infix -.

478Definition namedname : string lhs : bool cs : listascii st : listframe : step ≔
match cs with
c :: cs′
⇒
→
Nextcs′ FAppname [ ] :: st MTermfalse
else
valueTAtomname lhs cs st
[ ]
⇒
valueTAtomname lhs cs st

The names SWI-Prolog has as prefix operators. table − x is to it table(-(x)), so such an atom is not taken as the left side of an infix -. The symbol atoms that are prefix operators (-, +, \) are refused there with every other symbol atom.

490Definition prefix_names: liststring ≔
"discontiguous"; "dynamic"; "initialization"; "meta_predicate"; "module_transparent"; "multifile"; "public"; "table"; "thread_initialization"; "thread_local"; "volatile"%string

Whether v is an atom SWI has as a prefix operator.

496Definition is_prefix_namev : term : bool ≔
match v with
_
⇒
false

Whether cs, the text after a - that follows a term, starts the right side of an infix - the reader takes: after layout and comments, a name, a quoted atom or a list. The character just after the - must not be a symbol character or a full stop, so the - is an atom of its own, nor a digit: a right side that is a number is refused.

508Definition minus_rightcs : listascii : bool ≔
match cs with
[ ]
⇒
false
c :: _
⇒
→
false
else
match skipInLayout cs with
Somed :: _
⇒
let n ≔ coded in
is_lowern || n =? c_squote || n =? c_lbracket
_
⇒
false

Whether cs, the text after a full stop, makes that full stop a clause's end: the text ends there, or layout or a % follows.

524Definition ends_clausecs : listascii : bool ≔
match cs with
[ ]
⇒
true
c :: _
⇒

The step from what follows the term v, cs being the text after it from its first character that is not layout: a comma puts v in the compound or list it is in, a closing bracket ends that, a full stop ends the clause, and a - starts the right side of an infix -. Anything else is refused, so a term never runs into the token after it.

536Definition sep_stepv : term lhs : bool cs : listascii st : listframe : step ≔
match cs with
[ ]
⇒
c :: cs′
⇒
let n ≔ codec in
n =? c_comma
→
match st with
FAppf args :: st′
⇒
Nextcs′ FAppf v :: args :: st′ MTermfalse
FListelems :: st′
⇒
Nextcs′ FListv :: elems :: st′ MTermfalse
_
⇒
n =? c_rparen
→
match st with
FAppf args :: st′
⇒
valueTAppf rev_appendargs v true cs′ st′
_
⇒
→
match st with
FListelems :: st′
⇒
valueTListrev_appendelems v true cs′ st′
_
⇒
n =? c_dot
→
match st with
[ ]
⇒
→
Clausev cs′
else
_
⇒
n =? c_minus
→
lhs && minus_rightcs′ && negbis_prefix_namev
→
Nextcs′ FMinusv :: st MTermfalse
else
else

Whether name is a name whose compounds SWI-Prolog writes in a form of their own: '[|]'(a, []) is to it the list a, and '{}'(a) is a. A quoted atom of such a name is refused where a ( follows it.

573Definition is_special_namename : string : bool ≔
String.eqbname "[|]" || String.eqbname "{}"

The step from the start of a term, cs being the text from its first character that is not layout: a name, a quoted atom, a string, an integer (a - just before a digit makes it negative), a symbol atom, !, ;, {}, or the [ of a list. With first a ] gives the empty list. At the end of the text the reader is done if it is inside no term. fuel is at least the length of cs. Any other character is refused: a capital letter or an underscore starts a variable.

584Definition term_stepfuel : nat first : bool cs : listascii st : listframe : step ≔
match cs with
[ ]
⇒
match st with
[ ]
⇒
_
⇒
c :: cs′
⇒
let n ≔ codec in
→
let name, cs′′ ≔ identcs′ c in
namedname true cs′′ st
→
let z, cs′′ ≔ digitscs 0%Z in
valueTIntz true cs′′ st
n =? c_squote
→
match quotedfuel c_squote cs′ [ ] with
Somebs, cs′′
⇒
let name ≔ string_of_revbs in
else
namedname true cs′′ st
None
⇒
n =? c_dquote
→
match quotedfuel c_dquote cs′ [ ] with
Somebs, cs′′
⇒
valueTListcharsbs [ ] [ ] true cs′′ st
None
⇒
→
Nextcs′ FList[ ] :: st MTermtrue
→
match st with
FList[ ] :: st′
⇒
first
→
valueTList[ ] true cs′ st′
else
_
⇒
n =? c_minus && is_digitcodehdc cs′
→
let z, cs′′ ≔ digitscs′ 0%Z in
valueTInt−z true cs′′ st
→
match symbolscs′ c with
Somename, cs′′
⇒
namedname false cs′′ st
None
⇒
n =? c_bang || n =? c_semicolon
→
namedstring_of_revc true cs′ st
n =? c_lbrace && startsc_rbrace cs′
→
valueTAtom"{}" true tlcs′ st
else

One step of the reader on the text cs, inside the frames st and in the mode m. A step that is not the last takes at least one character of the text.

631Definition read_stepfuel : nat cs : listascii st : listframe m : mode : step ≔
match skipInLayout cs with
None
⇒
Somecs′
⇒
match m with
MTermfirst
⇒
term_stepfuel first cs′ st
MSepv lhs
⇒
sep_stepv lhs cs′ st

Clauses

Whether t is the atom end_of_file, which ends the text where it is a clause, as the end of the file does.

645Definition is_end_of_filet : term : bool ≔
match t with
⇒
String.eqba "end_of_file"
_
⇒
false

The clauses of the text cs, last first and in front of acc, the reader being inside the frames st in the mode m. Nothing when a step is refused. fuel is more than the length of cs, and so never runs out.

655Fixpoint clausesfuel : nat cs : listascii st : listframe m : mode acc : listterm : optionlistterm ≔
match fuel with
O
⇒
None
Sfuel′
⇒
match read_stepfuel′ cs st m with
⇒
None
⇒
Someacc
Clauset cs′
⇒
→
Someacc
else
clausesfuel′ cs′ [ ] MTermfalse t :: acc
Nextcs′ st′ m′
⇒
clausesfuel′ cs′ st′ m′ acc

The length of cs more than n. The standard library's length is not a tail call in the extracted code.

671Fixpoint countcs : listascii n : nat : nat ≔
match cs with
[ ]
⇒
n
_ :: cs′
⇒
countcs′ Sn

The clauses of the text cs, last first, or nothing.

678Definition rev_clausescs : listascii : optionlistterm ≔
clausesScountcs 0 cs [ ] MTermfalse [ ]

The clauses of the text cs in order, up to its end or to a clause that is the atom end_of_file, as read_term/3 reads them one after another. Nothing when SWI-Prolog would not read the text, and for the syntax this reader does not take.

685Definition read_clausescs : listascii : optionlistterm ≔
match rev_clausescs with
Somer
⇒
Somerev_appendr [ ]
None
⇒
None

Whether t is a run(Fn, Args) clause, which is no item.

692Definition is_runt : term : bool ≔
match t with
TAppf _; _
⇒
String.eqbf "run"
_
⇒
false

Whether t is an item of a module: a func/5, data/4, alias/3 or context/2 term.

700Definition is_itemt : term : bool ≔
match t with
TAppf _; _; _; _; _
⇒
String.eqbf "func"
TAppf _; _; _; _
⇒
String.eqbf "data"
TAppf _; _; _
⇒
String.eqbf "alias"
TAppf _; _
⇒
String.eqbf "context"
_
⇒
false

The items among the clauses r, which are given last first, in order and in front of acc: a run/2 clause is left out. Nothing when a clause is neither, where read_ir_file/3 throws.

713Fixpoint itemsr : listterm acc : listterm : optionlistterm ≔
match r with
[ ]
⇒
Someacc
t :: r′
⇒
→
itemsr′ t :: acc
→
itemsr′ acc
else
None

The module of the IR text cs, module(Items), as read_ir_file/3 gives it and nanofilread − terms prints it: every item in order, not validated. Nothing when Prolog would throw, and for the syntax this reader does not take.

726Definition read_modulecs : listascii : optionterm ≔
match rev_clausescs with
Somer
⇒
match itemsr [ ] with
Somel
⇒
SomeTApp"module" TListl
None
⇒
None
None
⇒
None

A text in pieces

The list of a large file's bytes takes far more room than the file: 24 bytes a character in the extracted reader. So the driver gives the text a piece at a time, and the reader asks for the next piece when it has read the whole clauses of the ones it has.

A text in pieces: its end, or its next characters and the rest, which is made when asked for.

746Inductive chunked: Type ≔
|TextEnd
|TextPiece
cs : listascii rest : unit → chunked

What reading the whole clauses of a piece gives: the clauses so far, last first, and either the end, at an end_of_file clause, or the text rest that is left, from the start of the first clause that is not whole.

754Inductive piece_end: Type ≔
|PieceStop
acc : listterm
|PieceMore
acc : listterm rest : listascii

The whole clauses at the front of the text start, which is not the text's end, in front of acc. The reader is at cs inside the frames st in the mode m, within the clause that starts at start. A clause is whole when a character follows its full stop: then no more text changes how it is read. A refusal, or the end of the characters, is not taken as such here, since more text may follow: the clause is left to be read again.

765Fixpoint piece_clausesfuel : nat start cs : listascii st : listframe m : mode acc : listterm : piece_end ≔
match fuel with
O
⇒
PieceMoreacc start
Sfuel′
⇒
match read_stepfuel′ cs st m with
⇒
PieceMoreacc start
Clauset rest
⇒
match rest with
[ ]
⇒
PieceMoreacc start
_ :: _
⇒
else
piece_clausesfuel′ rest rest [ ] MTermfalse t :: acc
Nextcs′ st′ m′
⇒
piece_clausesfuel′ start cs′ st′ m′ acc

The clauses of the text p, last first and in front of acc, buf being the characters before it that are not yet read. Only the last characters, with the text's end after them, are read as clauses reads a whole text.

787Fixpoint text_clausesp : chunked buf : listascii acc : listterm : optionlistterm ≔
match p with
⇒
clausesScountbuf 0 buf [ ] MTermfalse acc
TextPiececs rest
⇒
let all ≔ rev_appendrev_appendbuf [ ] cs in
match piece_clausesScountall 0 all all [ ] MTermfalse acc with
PieceStopacc′
⇒
Someacc′
PieceMoreacc′ buf′
⇒
text_clausesresttt buf′ acc′

The module of the IR text p, as read_module gives it for the characters of p's pieces one after another. That the two agree is not proved; tests/read.sh holds this one to Prolog with pieces of one character and of seven, and the examples below cut a text at every place.

803Definition read_textp : chunked : optionterm ≔
match text_clausesp [ ] [ ] with
Somer
⇒
match itemsr [ ] with
Somel
⇒
SomeTApp"module" TListl
None
⇒
None
None
⇒
None

The text cs in pieces of k characters, for a k above zero and a fuel of at least the length of cs.

815Fixpoint cutfuel k : nat cs : listascii : chunked ≔
match fuel, cs with
Sfuel′, _ :: _
⇒
TextPiecefirstnk cs λ_ ⇒ cutfuel′ k skipnk cs
_, _
⇒

Examples

A run is left out, a comment is passed over, and a phi's edge is the one operator.

825Example read_module_items: read_modulelist_ascii_of_string"run(f, [1]). % a run context(a, [start-const(-2), 'two words', ""hi""])." = SomeTApp"module" TListTApp"context" TAtom"a"; TListTApp"-" TAtom"start"; TApp"const" TInt−2; TAtom"two words"; TListTAtom"h"; TAtom"i"
Proof 1 step Qed
reflexivity

An escape in a quoted atom is its character, in UTF-8.

835Example read_module_escape: read_modulelist_ascii_of_string"context(a, 'p\n\xe9\q')." = SomeTApp"module" TListTApp"context" TAtom"a"; TAtomString"p" Stringbyte10 Stringbyte195 Stringbyte169 "q"
Proof 1 step Qed
reflexivity

A variable, an operator other than the infix -, a clause that is no item and a text with no full stop are refused.

843Example read_module_refuses: mapλs ⇒ read_modulelist_ascii_of_strings "context(a, X)."; "context(a, 1 + 2)."; "foo(a)."; "context(a, b)"%string = None; None; None; None
Proof 1 step Qed
reflexivity

A text read in pieces of every size from one character to forty is read as the whole text is: here two clauses with a comment, a quoted atom with a full stop in it and an end_of_file that hides a clause the reader would refuse.

853Definition pieces_example: listascii ≔
list_ascii_of_string"context('a. b', [x-y, ""s""]). /* c. */ data(d, local, 8, []). end_of_file. foo(X)."
858Example read_text_pieces: forallbλk ⇒ match read_textcutlengthpieces_example Sk pieces_example, read_modulepieces_example with Somea, Someb ⇒ term_eqba b | _, _ ⇒ false end seq0 40 = true
Proof 2 steps Qed
vm_compute
reflexivity

A text that is refused is refused in pieces too.

868Example read_text_refuses: forallbλk ⇒ match read_textcut40 Sk list_ascii_of_string"context(a, b). context(a, X)." with None ⇒ true | Some_ ⇒ false end seq0 30 = true
Proof 2 steps Qed
vm_compute
reflexivity