@josd/eyecode 0.0.0-stage → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/SPEC.md ADDED
@@ -0,0 +1,921 @@
1
+ # <img src="assets/eye.png" alt="" width="48" height="48" align="absmiddle"> eyecode specification
2
+
3
+ ```text
4
+ Title: The eyecode Rule Language and Proof Format
5
+ Version: eyecode 0.1.3
6
+ Status: Informational
7
+ Author: Jos De Roo, KNoWS office of IDLab, Ghent University - imec
8
+ Repository: https://github.com/eyereasoner/eyecode
9
+ ```
10
+
11
+ ## Abstract
12
+
13
+ eyecode is a rule language written in JavaScript, with forward and backward
14
+ reasoning, and a proof format whose documents a separate checker verifies
15
+ against the program that produced them. This document specifies the terms
16
+ the language reasons over, how a program is stated in JavaScript, what a
17
+ program concludes, the canonical text in which terms, conclusions, proofs and
18
+ check reports are written and read back, the proof document, the seven
19
+ conditions (C1-C7) a proof checker establishes, the check report, and the
20
+ command line.
21
+
22
+ ## Status of This Memo
23
+
24
+ This document is not an Internet Standards Track specification. It describes
25
+ the language and formats as implemented by eyecode 0.1.3, for readers who want
26
+ to write programs, produce or consume proofs and reports, or implement a
27
+ compatible reasoner or checker. Where this document and the implementation
28
+ disagree, that is a defect in one of them.
29
+
30
+ ## Table of Contents
31
+
32
+ 1. [Introduction](#1-introduction)
33
+ 2. [Conventions and Terminology](#2-conventions-and-terminology)
34
+ 3. [Terms](#3-terms)
35
+ 4. [Programs](#4-programs)
36
+ 5. [Goals, Controls and Primitives](#5-goals-controls-and-primitives)
37
+ 6. [Arithmetic](#6-arithmetic)
38
+ 7. [Reasoning](#7-reasoning)
39
+ 8. [Canonical Text](#8-canonical-text)
40
+ 9. [Reading Documents](#9-reading-documents)
41
+ 10. [Proof Documents](#10-proof-documents)
42
+ 11. [Proof Checking](#11-proof-checking)
43
+ 12. [Check Reports](#12-check-reports)
44
+ 13. [Unused Clauses](#13-unused-clauses)
45
+ 14. [Command Line](#14-command-line)
46
+ 15. [Security Considerations](#15-security-considerations)
47
+ 16. [Conformance](#16-conformance)
48
+ - [Appendix A. Document Grammar](#appendix-a-document-grammar)
49
+ - [Appendix B. Example](#appendix-b-example)
50
+
51
+ ---
52
+
53
+ ## 1. Introduction
54
+
55
+ An eyecode program states facts and rules. Forward rules are applied until no
56
+ new conclusion follows; backward rules are applied when a goal asks for them.
57
+ Every conclusion can be accompanied by a proof: a document that names, for
58
+ each step, the program clause or primitive that justifies it. A checker that
59
+ never consults the reasoner verifies such a document against the program and
60
+ reports, condition by condition, what it established and what it had to take
61
+ on trust.
62
+
63
+ Programs are JavaScript scripts. Conclusions, proofs and check reports are
64
+ JavaScript expressions, one per line, which a reader turns back into terms
65
+ without executing them. One language thus states the rules, computes with
66
+ them, and holds every result.
67
+
68
+ ## 2. Conventions and Terminology
69
+
70
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
71
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY" and "OPTIONAL" in this document
72
+ are to be interpreted as described in BCP 14 (RFC 2119, RFC 8174) when, and
73
+ only when, they appear in all capitals.
74
+
75
+ - **Term**: a value the language reasons over (Section 3).
76
+ - **Clause**: a fact, a forward rule or a backward rule (Section 4).
77
+ - **Goal**: a term solved by resolution or by a primitive (Section 5).
78
+ - **Substitution**: a mapping from variable names to terms.
79
+ - **Instance**: a term obtained from another by applying a substitution.
80
+ - **Identical**: two terms are identical when their canonical texts
81
+ (Section 8) are equal; variables are identical only to themselves.
82
+ - **Ground**: containing no variable.
83
+ - **Conclusion**: a term a run reports (Section 7.6).
84
+ - **Document**: text holding a sequence of expressions (Sections 9-12).
85
+ - **Reasoner**: an implementation of Sections 3-10, which checks its own
86
+ proofs as Section 11 describes.
87
+ - **Checker**: an implementation of Sections 9, 11 and 12.
88
+
89
+ ## 3. Terms
90
+
91
+ A term is one of:
92
+
93
+ | Kind | Representation | Example |
94
+ | --- | --- | --- |
95
+ | Atom | a JavaScript string | `'socrates'`, `'[]'` |
96
+ | Integer | a JavaScript `BigInt`, of unbounded size | `42`, `-7` |
97
+ | Float | a JavaScript number that is a float, an IEEE-754 binary64 value | `0.5`, `1e+22`, `2.0` |
98
+ | Variable | a name | `X`, `_Rest` |
99
+ | Compound | a name (an atom) and one or more argument terms | `parent('alice', 'bob')` |
100
+
101
+ A compound term is identified by its name and its arity, the number of its
102
+ arguments, written `name/arity`. An atom used as a goal has arity 0.
103
+
104
+ **Lists.** The empty list is the atom `'[]'`. A non-empty list is the
105
+ compound `'.'(Head, Tail)`. A list whose final tail is not `'[]'` is an open
106
+ list. Character text is a list of one-character atoms.
107
+
108
+ **Numbers.** Integers and floats are distinct: `1` and `1.0` MUST NOT unify.
109
+ Floats MUST be finite; no operation produces an infinity or a NaN as a term
110
+ (Section 6). Nonfinite JavaScript values and float literals that overflow,
111
+ such as `1e999`, MUST be rejected in programs, goals and documents. Booleans,
112
+ `null` and `undefined` are not terms.
113
+
114
+ **Unification** is syntactic unification on finite trees. It MUST apply the
115
+ occurs check: binding a variable to a term that contains it fails. Atoms unify
116
+ when their texts are equal; numbers when they are of the same kind and equal;
117
+ compounds when their names and arities are equal and their arguments unify
118
+ pairwise.
119
+
120
+ **Standard order.** Terms are totally ordered as: variables, then numbers,
121
+ then atoms, then compounds. Numbers are ordered by value, compared exactly
122
+ across integers and floats; a float precedes an integer of equal value.
123
+ Atoms are ordered by the code points of their characters. Compounds are
124
+ ordered by arity, then name, then arguments from left to right. Distinct
125
+ variables are ordered by the code points of their names, so the order is the
126
+ same in every comparison. The names of renamed-apart variables (Section 7.1)
127
+ are implementation-specific, so a program SHOULD NOT depend on the relative
128
+ order of two distinct unbound variables.
129
+
130
+ ## 4. Programs
131
+
132
+ ### 4.1 Program scripts
133
+
134
+ A program is a JavaScript script, run in sloppy mode with every name it does
135
+ not declare resolved as Section 4.3 says. It needs no import. Running the
136
+ script states the program's clauses in the order the calls are made; `fact`
137
+ MAY state several clauses in one call (Section 4.2). Several scripts MAY be
138
+ loaded as one program; their clauses are then numbered in the order the
139
+ scripts are run.
140
+
141
+ A program is given exactly the names needed to state it: the statements of
142
+ Section 4.2, `preds`, `vars`, `struct`, the controls and primitives of
143
+ Section 5, the atom `fail`, and `eyecode`, the library, with which a program
144
+ can build and run another program and read and write documents
145
+ (`eyecode.build`, `eyecode.run`, `eyecode.checkProof`, `eyecode.checkReport`,
146
+ `eyecode.verdictText`, `eyecode.readTerm`, `eyecode.readTerms`, `eyecode.write`).
147
+
148
+ ### 4.2 Statements
149
+
150
+ | Statement | Clause stated |
151
+ | --- | --- |
152
+ | `fact(T1, T2, ...)` | One fact per argument. |
153
+ | `implies(Premise, Conclusion)` | A forward rule: the premise's goals are its body and the conclusion its head, or its heads when the conclusion is an array of them. |
154
+ | `implied_by(Conclusion, Premise)` | A backward rule: the conclusion is its head and the premise's goals are its body. |
155
+ | `query(G1, G2, ...)` | A forward rule with the head `'true'` and the body `G1, G2, ...`: it reports its body's instances (Section 7.2). At least one goal is REQUIRED. |
156
+ | `contradiction(G1, G2, ...)` | A forward rule with the head `'false'` and the body `G1, G2, ...`: it halts the run (Section 7.2). At least one goal is REQUIRED. |
157
+ | `facts_from(path)` or `facts_from({text: ...})` | One fact per expression of a document (Section 9). |
158
+
159
+ A premise is a goal or an array of goals, their conjunction (Section 5.1). A
160
+ body goal that is a conjunction is split into its conjuncts; the clause body
161
+ is the resulting sequence of goals.
162
+
163
+ Clauses are numbered from 1 in the order they are stated. Each clause records
164
+ the line of the program on which the statement stating it begins; the facts
165
+ of `facts_from` record the line of that call.
166
+
167
+ `facts_from` is how a program takes in data that is not a program: a document
168
+ of plain expressions, one per line, such as the conclusions, proof or check
169
+ report of another run, or data from a source that is not trusted. The
170
+ document is read as Section 9 describes and is never executed, so it can only
171
+ ever state facts. A data file written as a program instead (`fact(...)`
172
+ statements) would run as JavaScript code.
173
+
174
+ A clause MUST be rejected when:
175
+
176
+ - a head is not an atom or a compound;
177
+ - a head is `step/4` or `clause/2`, which are reserved for proof documents;
178
+ - a head is a primitive (Section 5.2) or a control (Section 5.1), except the
179
+ head `'true'` of a query and `'false'` of a contradiction; in particular a
180
+ conclusion of `implies` is never `'true'` or `'false'`;
181
+ - a body goal is not a variable, an atom or a compound, or is an empty array.
182
+
183
+ ### 4.3 Names a program does not define
184
+
185
+ A name a program uses without declaring it (with `const`, `let`, `var`,
186
+ `function` or `class`, or by assigning to it) is supplied as follows:
187
+
188
+ 1. a name the program is given (Section 4.1) has that meaning;
189
+ 2. the JavaScript globals `Math`, `JSON`, `BigInt`, `Infinity`, `NaN`,
190
+ `undefined`, `console`, `globalThis`, `parseInt`, `parseFloat`, `isNaN`
191
+ and `isFinite` keep their meaning;
192
+ 3. any other name beginning with an uppercase letter or `_` is the variable of
193
+ that name, so that `Date`, `Map` or `Object` are variables as logic
194
+ programs name them (`globalThis.Date` still reaches the global);
195
+ 4. any other name is the predicate of that name: calling it with arguments
196
+ builds the compound with that name, calling it without arguments or using
197
+ it uncalled stands for the atom of that name.
198
+
199
+ A program MAY name predicates and variables explicitly, which it MUST do for
200
+ a predicate named like a name of rules 1 or 2 or a variable whose name begins
201
+ with a lowercase letter: `const [p, q] = preds('p q')` and
202
+ `const [X, Y] = vars('X Y')`, where one name gives the predicate or variable
203
+ itself rather than an array.
204
+
205
+ A top-level expression statement that calls a predicate supplied by rule 4,
206
+ such as a misspelled `fcat(p(1))`, states nothing; a loader MUST report it as
207
+ an error rather than ignore it.
208
+
209
+ ### 4.4 Terms in a program
210
+
211
+ Within a program, a JavaScript string is an atom and a `BigInt` an integer. A
212
+ finite JavaScript number is an integer when it is integral and a float
213
+ otherwise: `2` and `2.0` are both the integer 2, and `float(2)` is the float
214
+ 2.0. An integer beyond 2^53 is written as a `BigInt` literal, such as
215
+ `9007199254740993n`, since a number literal would already have rounded it. An
216
+ array is a list, and `[H, ...T]` the list with head `H` and tail `T`.
217
+ `struct('name', A1, ...)` builds a compound with any name, and
218
+ `struct('name')` the atom. Every occurrence of `_` in a clause is a distinct
219
+ variable, an **anonymous variable**: the occurrences are named `_0`, `_1`,
220
+ ... in the order of the clause's text, skipping names the clause already
221
+ uses, and clause displays and bindings (Section 10) show these names. A
222
+ program SHOULD NOT name its own variables `_` followed by digits, which
223
+ Section 5.1 treats as anonymous.
224
+
225
+ In a goal position, an array is the conjunction of its items: a statement's
226
+ goal, the argument of `and`, `or`, `not`, `call` and `once`, and the goal of
227
+ `findall`. Anywhere else an array is a list.
228
+
229
+ Operators do not build terms. Variables, compounds and predicates have no
230
+ JavaScript primitive value, so an operator applied to one, such as `X + 1` or
231
+ `X > 1`, MUST raise an error that says what to write instead: `add(X, 1)`,
232
+ `gt(X, 1)`. An operator applied only to plain JavaScript values is
233
+ JavaScript's own: `3 + 4` is the integer 7, and `1 < 2` is the JavaScript
234
+ `true`, which is not a term, so stating it is an error.
235
+
236
+ ### 4.5 Stratification
237
+
238
+ A body goal depends on a clause when the goal, renamed apart, unifies with
239
+ one of the clause's heads. The dependency is **closed** when the goal occurs
240
+ inside a negation or as the goal of a collection (Section 5.1), and **open**
241
+ otherwise. Each clause has a rank: the least assignment such that a clause's
242
+ rank is at least the rank of every clause it depends on, plus one for a closed
243
+ dependency. Forward rules run in order of rank (Section 7.2).
244
+
245
+ A program MUST be rejected when:
246
+
247
+ - no such assignment exists ("unstratified negation or collection
248
+ dependency"), that is, a closed dependency lies on a cycle;
249
+ - a forward rule can reach, through dependencies, a clause with a body goal
250
+ that is a variable ("forward dependencies require statically named calls").
251
+
252
+ Because dependencies compare whole terms, two relations sharing a predicate
253
+ name MAY have different ranks.
254
+
255
+ ## 5. Goals, Controls and Primitives
256
+
257
+ ### 5.1 Controls
258
+
259
+ | Control | Term | Meaning |
260
+ | --- | --- | --- |
261
+ | `and(A, B)`, `[A, B]` | `and(A, B)` | Conjunction: solve `A`, then `B`. |
262
+ | `or(A, B)` | `or(A, B)` | Disjunction: the solutions of `A`, then those of `B`. |
263
+ | `not(G)` | `not(G)` | Negation: succeeds once, binding nothing, when `G` has no solution. When the negation is solved, every variable of `G` MUST be bound except anonymous ones, which stand for any value: `not(q(X, _))` succeeds when `q(X, Y)` has no solution for any `Y`. A named unbound variable is an error. |
264
+ | `call(G)` | `call(G)` | The solutions of `G`. |
265
+ | `once(G)` | `once(G)` | The first solution of `G`. |
266
+ | `findall(T, G, L)` | `findall(T, G, L)` | Unifies `L` with the list of instances of `T`, one per solution of `G`, in order, each renamed apart. |
267
+
268
+ A variable is anonymous when its name, up to any `#` a renaming apart
269
+ (Section 7.1) adds, is `_` followed by digits (Section 4.4), or is one a
270
+ reader made for a `_` (Section 9).
271
+
272
+ Conjunction and disjunction are binary. In a program, `and` and `or` with
273
+ more than two goals build the chain from the left, `and(A, B, C)` being
274
+ `and(and(A, B), C)`, and `or` with one goal is that goal. `not`, `call` and
275
+ `once` with several goals take their conjunction. A goal text (Section 9)
276
+ reads `and` and `or` with more than two arguments the same way.
277
+
278
+ ### 5.2 Primitives
279
+
280
+ In a flow pattern, `+` marks an argument that MUST be bound when the goal
281
+ runs, `-` one that MUST be unbound, `?` either, and `@` one only inspected. A
282
+ primitive called outside its patterns raises an error.
283
+
284
+ | Primitive | Pattern | Meaning |
285
+ | --- | --- | --- |
286
+ | `'true'`, `'fail'`, `'false'` | | Succeeds; fails; fails. |
287
+ | `unify(?X, ?Y)` | | Unifies `X` and `Y`. |
288
+ | `not_unify(@X, @Y)` | | Succeeds, binding nothing, when `X` and `Y` do not unify. |
289
+ | `identical(@X, @Y)` | | `X` and `Y` are identical. |
290
+ | `not_identical(@X, @Y)` | | `X` and `Y` are not identical. |
291
+ | `compare(?O, @X, @Y)` | | Unifies `O` with `'<'`, `'='` or `'>'`, by the standard order. |
292
+ | `is(?V, +E)` | | Evaluates `E` (Section 6) and unifies `V` with the result. |
293
+ | `eq(+E1, +E2)`, `ne(+E1, +E2)` | | The values of `E1` and `E2` are equal, or not. |
294
+ | `lt(+E1, +E2)`, `le(+E1, +E2)`, `gt(+E1, +E2)`, `ge(+E1, +E2)` | | Compares the values of `E1` and `E2`. |
295
+ | `is_var(@X)`, `is_nonvar(@X)` | | `X` is an unbound variable, or is not. |
296
+ | `is_ground(@X)` | | `X` contains no unbound variable. |
297
+ | `is_atom(@X)`, `is_number(@X)` | | `X` is an atom, or a number. |
298
+ | `is_int(@X)`, `is_float(@X)` | | `X` is an integer, or a float. |
299
+ | `is_compound(@X)` | | `X` is a compound; a non-empty list is one. |
300
+ | `functor` | `functor(+T, ?N, ?A)`, `functor(-T, +N, +A)` | Name and arity of `T`, or `T` built with fresh variable arguments. `A` MUST be between 0 and 1024. |
301
+ | `arg` | `arg(+N, +T, ?A)` | `A` is the `N`th argument of `T`, counting from 1. |
302
+ | `univ` | `univ(+T, ?L)`, `univ(-T, +L)` | `L` is the list of `T`'s name and arguments. |
303
+ | `atom_chars` | `atom_chars(+A, ?L)`, `atom_chars(-A, +L)` | `L` is the list of `A`'s characters as atoms. |
304
+ | `atom_codes` | `atom_codes(+A, ?L)`, `atom_codes(-A, +L)` | `L` is the list of `A`'s character code points. |
305
+ | `atom_length` | `atom_length(+A, ?N)` | `N` is the number of characters of `A`. |
306
+ | `atom_concat` | `atom_concat(+A, +B, ?AB)`, `atom_concat(?A, ?B, +AB)` | `AB` is `A` followed by `B`; with `AB` given, every split, shortest `A` first. |
307
+
308
+ A character is a Unicode code point. Every primitive except `atom_concat` has
309
+ at most one solution. Primitives MUST be pure: their solutions depend only on
310
+ their arguments. A primitive given an argument of the wrong kind for its
311
+ patterns raises an error, as `atom_length(123, N)` does; one given arguments
312
+ of the right kinds that has no solution fails, as `arg(5, f(1), A)` does.
313
+
314
+ A goal whose name and arity are neither a control, a primitive nor the head
315
+ of any clause has no solution.
316
+
317
+ ## 6. Arithmetic
318
+
319
+ An expression term is evaluated as follows:
320
+
321
+ - a number is its value; the atoms `'pi'`, `'e'` and `'tau'` are π, e and
322
+ 2π; a variable bound to an expression is that expression's value; an
323
+ unbound variable or any other atom is an error;
324
+ - `add`, `sub`, `mul`, `div`, `floordiv`, `mod`, `pow`, `shl`, `shr` and
325
+ `xor` with two arguments are addition, subtraction, multiplication, true
326
+ division, floor division, modulo, power, shifts and exclusive or; `and` and
327
+ `or` with two arguments are bitwise and and or; `not`, `neg` and `pos` with
328
+ one argument are bitwise inversion, negation and identity;
329
+ - the functions `abs`, `min`, `max` (with two or more arguments), `round`
330
+ (with one or two), `int`, `float`, `floor`, `ceil`, `trunc`, `sqrt`,
331
+ `isqrt`, `exp`, `log` (with one or two: a value and a base), `log2`,
332
+ `log10`, `sin`, `cos`, `tan`, `asin`, `acos`, `atan`, `atan2`, `sinh`,
333
+ `cosh`, `tanh`, `hypot`, `degrees`, `radians`, `fmod`, `copysign`, `gcd`
334
+ and `lcm`.
335
+
336
+ Integers are exact and unbounded. An operation on integers gives an integer,
337
+ except `div`, which always gives a float, and `pow` with a negative exponent.
338
+ An operation with a float operand gives a float. `floordiv` rounds toward
339
+ negative infinity and `mod` takes the sign of its divisor: `floordiv(-7, 3)`
340
+ is -3 and `mod(-7, 3)` is 2. `div` of two integers is the float nearest to
341
+ their exact quotient. `round` rounds half to even, to an integer with one
342
+ argument and to the given number of decimals with two; `int`, `floor`, `ceil`
343
+ and `trunc` give integers. A float is written as Section 8.1 says.
344
+
345
+ An evaluation MUST raise an error, rather than produce a value, on a division
346
+ or modulo by zero, a domain error (such as `sqrt(-1)` or `log(0)`), a bitwise
347
+ operation or `gcd` on a float, when the result is not a finite real number,
348
+ or when a power or left shift would need more than 2^26 bits: for a power of
349
+ integers `pow(A, B)` with `B > 0` and `abs(A) > 1`, when `B` times the bit
350
+ length of `A` exceeds 2^26; for a shift `shl(A, B)` of integers, when `B`
351
+ exceeds 2^26.
352
+
353
+ Comparisons are primitives (Section 5.2), not arithmetic functions: `lt` and
354
+ the other comparisons in an expression are an error. Comparison primitives
355
+ compare values exactly, including across integers and floats.
356
+
357
+ ## 7. Reasoning
358
+
359
+ ### 7.1 Search
360
+
361
+ Goals are solved depth-first, left to right. A goal is solved, in order:
362
+
363
+ 1. by a control or primitive (Section 5), when it is one;
364
+ 2. otherwise against the facts derived so far by forward rules with the same
365
+ name and arity, in the order they were derived;
366
+ 3. then against the program's facts and backward rules with the same name and
367
+ arity, in clause order, each renamed apart before it is unified with the
368
+ goal; a rule's body is then solved in its place.
369
+
370
+ Renaming a clause apart gives each of its variables a fresh variable whose
371
+ name is the variable's name followed by `#` and an implementation-specific
372
+ suffix. Such names never appear in the documents a run writes (Section 8.3).
373
+
374
+ An implementation MAY index clauses, provided the order above is kept.
375
+
376
+ ### 7.2 Forward reasoning
377
+
378
+ Forward rules run stratum by stratum, in increasing rank (Section 4.5). Within
379
+ a stratum, rounds are repeated until a round adds no new fact. In a round,
380
+ each rule in clause order is renamed apart and its body solved against the
381
+ current state; all solutions of the body are collected first, then each is
382
+ concluded:
383
+
384
+ - a head variable the solution leaves unbound is bound to a **Skolem term**
385
+ `skolem(Rule, Variable, Arguments)`: `Rule` is the clause number of the
386
+ rule, `Variable` the variable's name as the program writes it (an
387
+ anonymous one as `_0`, `_1`, ..., Section 4.4), and `Arguments` the list of
388
+ the ground values the solution gives the heads' other variables, in order
389
+ of their first occurrence in the heads. A Skolem term is thus a function of
390
+ the activation: the rule and the instance of its heads. The same activation
391
+ gives the same terms, in any round and in any run, and different
392
+ activations give different terms; variables shared between heads stay
393
+ shared. A variable that a value of the solution brought in, rather than a
394
+ head variable, is named after its own variable, followed by `1`, `2`, ...
395
+ when that name is taken. A rule that keeps meeting new activations does
396
+ not terminate (Section 7.3). Derived facts are therefore ground;
397
+ - a head `'true'` reports the instance of the rule's body, as a conjunction,
398
+ once per distinct instance (by identity of canonical text);
399
+ - a head `'false'` records the conclusion `'false'` and stops all reasoning
400
+ with halt code 65;
401
+ - any other head is added as a derived fact unless an identical fact is
402
+ already derived or is a ground fact of the program.
403
+
404
+ When the run asks its own goals (Section 7.4), rules whose heads are all
405
+ `'true'` are not run.
406
+
407
+ ### 7.3 Bounds
408
+
409
+ A run is bounded by `max_depth`, the depth of nested rule bodies (default
410
+ 1000000), by `max_inferences`, the number of goals started (default
411
+ 1000000), and by `max_iterations`, the rounds per stratum (default 1000).
412
+ Exceeding a bound MUST raise an error; a partial result MUST NOT be returned
413
+ as complete.
414
+
415
+ ### 7.4 Goals
416
+
417
+ A run MAY be given goals. After forward reasoning, each goal is solved in
418
+ turn, and each solution is reported as the instance of its goal, unless an
419
+ instance identical up to renaming of its variables was already reported for
420
+ this goal or an earlier one of the same run.
421
+
422
+ ### 7.5 Halting
423
+
424
+ A run that concluded `'false'` has halt code 65; otherwise it has none.
425
+
426
+ ### 7.6 Conclusions
427
+
428
+ The conclusions of a run are, in order:
429
+
430
+ 1. when it halted: every derived fact, in the order derived, ending with
431
+ `'false'`;
432
+ 2. otherwise, when it was given goals: the reported instances of its goals;
433
+ 3. otherwise, when the program has a forward rule with a head `'true'`: the
434
+ reported instances, in order of first report, which MAY be none;
435
+ 4. otherwise: every derived fact, in the order derived.
436
+
437
+ The output of a run is the canonical text (Section 8) of each conclusion,
438
+ one per line.
439
+
440
+ ### 7.7 Proof recording
441
+
442
+ When a proof is requested, each solution records how each of its goals was
443
+ justified: by a fact or rule of the program, by a derived fact (whose own
444
+ record is kept), by a primitive, by a control, by an absence (a negation) or
445
+ by a collection (`findall`). For each conclusion the first derivation found
446
+ is recorded. A reasoner MUST check every proof it generates (Section 11)
447
+ before returning it, and MUST fail with an error rather than return a proof
448
+ that does not pass. A run without conclusions has a proof without claims,
449
+ which is valid and certifies nothing.
450
+
451
+ A goal such as `is_var(X)` followed by `unify(X, 'a')`
452
+ cannot be recorded faithfully by its final substitution, so such a run
453
+ cannot produce a proof.
454
+
455
+ ## 8. Canonical Text
456
+
457
+ Every term has exactly one canonical text, which is a JavaScript expression.
458
+
459
+ ### 8.1 Atoms, numbers, variables and lists
460
+
461
+ - An atom is written between single quotes, with `\\`, `\'`, and the
462
+ characters that need it escaped as `\n`, `\t`, `\r`, `\b`, `\f`, `\v`,
463
+ `\0`, `\xHH` or `\uHHHH`; `'[]'` is written `[]`.
464
+ - An integer is written in decimal. A float is written as the shortest
465
+ decimal that reads back as the same value, with at least one digit after
466
+ the point, in exponent form `1e+22` or `1e-05` when the exponent is below
467
+ -4 or at least 16: `0.1`, `2.0`, `-0.0`, `1e+22`.
468
+ - A variable is written as its name when the name is an ASCII identifier
469
+ (letters, digits and `_`, not starting with a digit), not a reserved word
470
+ of JavaScript, not `_` and does not begin with `VAR_`. Any other name is
471
+ written `VAR_` followed by the name with every ASCII letter and digit kept,
472
+ every `_` doubled and every other character `c` replaced by `_hex_` where
473
+ `hex` is the lowercase hexadecimal code point of `c`. The variable `X#12`
474
+ is thus written `VAR_X_23_12`. A reader decodes such a name back
475
+ (Section 9).
476
+ - A list is written `[I1, I2, ...]`; an open list ends with `, ...Tail`.
477
+
478
+ ### 8.2 Compounds
479
+
480
+ A compound is written `name(A1, A2, ...)` when its name is an ASCII
481
+ identifier, not a reserved word of JavaScript and not `struct`, and
482
+ `struct('name', A1, ...)` otherwise. Arguments are separated by `, `.
483
+ There are no operators: `add(X, 1)` is written `add(X, 1)`.
484
+
485
+ A chain of conjunctions or disjunctions built from the left,
486
+ `and(and(A, B), C)`, is written as one call, `and(A, B, C)`. A compound
487
+ `and/N` or `or/N` with more than two arguments is written with `struct`, as
488
+ `struct('and', A, B, C)`.
489
+
490
+ ### 8.3 Variables in written documents
491
+
492
+ The conclusions a run writes, its proof documents (Section 10) and check
493
+ reports (Section 12) do not show the names variables have inside a run. In
494
+ the conclusions of a run and in a proof document, the variables are named
495
+ `A`, `B`, ..., `Z`, `A1`, ..., `Z1`, `A2`, ... in the order the document
496
+ first shows them, across the whole document, the conclusions written first;
497
+ the clause displays of a proof keep the program's names. A check report
498
+ names the variables of each fact anew (Section 12). The bindings an
499
+ implementation reports for each answer to a goal SHOULD name its variables as
500
+ the answer does.
501
+
502
+ ## 9. Reading Documents
503
+
504
+ A document is UTF-8 text holding a sequence of JavaScript expression
505
+ statements. A statement ends at the end of its line, unless a bracket is
506
+ still open, or at a `;`; comments (`// ...` and `/* ... */`), blank lines and
507
+ indentation are ignored; each term records the line on which its statement
508
+ begins. The documents eyecode writes hold one statement per line. A reader
509
+ MUST NOT execute the text. It accepts exactly:
510
+
511
+ - a string literal between single or double quotes, with JavaScript's
512
+ escapes: the atom; a decimal integer literal, or one with the `BigInt`
513
+ suffix `n`, or a finite decimal float literal (one with a point or an
514
+ exponent): the number;
515
+ - a name: the variable of that name, where each `_` is a new anonymous
516
+ variable (Section 5.1) and a name starting with `VAR_` is decoded
517
+ (Section 8.1), or rejected when it encodes no name;
518
+ - a call of a plain name: the compound, or the atom when there are no
519
+ arguments; `struct('name', ...)` as in Section 8.2; `and` and `or` with
520
+ more than two arguments as in Section 5.1;
521
+ - an array literal: the list, where only the last item MAY be spread
522
+ (`...Tail`) and then is the tail; `[...T]` is `T`;
523
+ - an object literal `{K: V, ...}` whose keys are names or strings: the list
524
+ of compounds `'='(K, V)`, in order;
525
+ - a minus sign applied directly to a numeric literal: the negative number;
526
+ - an expression in parentheses: that expression.
527
+
528
+ A trailing comma is allowed in a call, an array and an object. Anything else
529
+ MUST be rejected: an operator, a property access, a subscript, a call of a
530
+ call, a spread argument, a comma expression, an assignment, a template
531
+ literal, a regular expression, a hexadecimal, octal or binary literal, a
532
+ numeric separator, an integer literal with a leading zero, the names `true`,
533
+ `false`, `null`, `undefined`, `NaN`, `Infinity` and the other reserved words,
534
+ a name containing `$`, an arrow function, a declaration, a raw control
535
+ character other than a tab in a string, and a nonbreaking space outside a
536
+ string. Reading the canonical text of a term MUST give the term back.
537
+
538
+ ## 10. Proof Documents
539
+
540
+ ### 10.1 Structure
541
+
542
+ A proof document is a document (Section 9) holding, in this order:
543
+
544
+ 1. the conclusions of the run (Section 7.6), one per line;
545
+ 2. an empty line;
546
+ 3. one `clause(N, Display)` per program clause the proof cites, by
547
+ increasing `N`;
548
+ 4. an empty line;
549
+ 5. one `step(Goal, By, Bindings, Uses)` per justified goal.
550
+
551
+ A checker MUST treat every statement that is neither `clause/2` nor `step/4`
552
+ as a claim, whatever its position.
553
+
554
+ ### 10.2 Clause displays
555
+
556
+ `Display` shows clause `N` as the program states it: `fact(Head)`,
557
+ `implies(Body, Head)`, `implied_by(Head, Body)`, `query(G1, ...)` or
558
+ `contradiction(G1, ...)`, where `Body` is the clause's one body goal, or the
559
+ array of its body goals when it has several, `Head` likewise the head or the
560
+ array of heads, and `G1, ...` are the body goals themselves. Displays are not
561
+ authority: a checker MUST compare each with the program it checks against.
562
+
563
+ ### 10.3 Steps
564
+
565
+ `Goal` is the justified goal as it stands once the whole solution is found:
566
+ the goal with every variable the solution bound replaced by its value. The
567
+ program's goal `unify(Y, 6)`, solved with `Y` unbound, thus has the step
568
+ `step(unify(6, 6), 'builtin', {}, [])`; the value `Y` received is recorded in
569
+ the bindings of the step that cites the clause, as `{Y: 6}`. Steps appear
570
+ in the order a depth-first walk
571
+ from the claims first meets each goal, and each distinct goal (by canonical
572
+ text) has one step. `Uses` is the list of the goals that justify `Goal`, in
573
+ order. `By` is one of:
574
+
575
+ | `By` | Meaning | `Bindings` | `Uses` |
576
+ | --- | --- | --- | --- |
577
+ | `clause(N)` | `Goal` is an instance of a head of clause `N`, a fact or a rule, whose body instance is `Uses`. | the clause's variables | the body instance, empty for a fact |
578
+ | `'builtin'` | `Goal` is a primitive that holds. | empty | empty |
579
+ | `'control'` | `Goal` is `call`, `once` or a disjunction, solved by `Uses`. | empty | the solved goals |
580
+ | `'absent'` | `Goal` is a negation taken on trust. | empty | empty |
581
+ | `'collected'` | `Goal` is a `findall` taken on trust. | empty | empty |
582
+
583
+ `Bindings` is an object from each variable name of the cited clause, as
584
+ the program wrote it, to its value in this step: `{X: 'socrates'}`. A
585
+ reasoner writes every variable of the clause, in the order the clause display
586
+ first shows them (for `implies`, the premise first);
587
+ a checker MUST accept any subset, since the goal and uses determine the
588
+ rest. A primitive has no variables of its own, so `'builtin'` steps have
589
+ empty bindings.
590
+
591
+ ## 11. Proof Checking
592
+
593
+ A checker is given a program, a proof document and, when the proof answers
594
+ goals asked from outside the program, those goals. It MUST NOT call a
595
+ reasoner to supply a missing step; it MAY recompute primitives. It
596
+ establishes seven conditions and records each failure with its condition, a
597
+ detail and, where there is one, the term concerned.
598
+
599
+ ### 11.1 Reading the document
600
+
601
+ The document MUST read (Section 9); otherwise C3 fails and the document has
602
+ no claims and no steps. Each `clause(N, Display)` MUST name a clause of the
603
+ program whose display (Section 10.2) is identical to `Display`; otherwise C1
604
+ fails. Each `step` MUST have bindings that read as a list of `'='/2` pairs,
605
+ as an object literal does, and a list of uses, and no two steps may have
606
+ identical goals; otherwise C3 fails and the step is set aside. Every other
607
+ statement is a claim (Section 10.1).
608
+
609
+ ### 11.2 C1 Resolution
610
+
611
+ For a `clause(N)` step, `N` MUST be a clause of the program. The clause,
612
+ renamed apart, MUST satisfy: each binding names a distinct variable of the
613
+ clause and unifies it with its value; and for one of the clause's heads
614
+ (each conjunct of a forward rule's head), the head unifies with `Goal` and
615
+ the body, of the same length as `Uses`, unifies with `Uses` pairwise, such
616
+ that afterwards the head is identical to `Goal` and each body goal to its
617
+ use. A step's own terms MUST NOT need further instantiation to match: a
618
+ source clause `same(X, X)` cannot justify `same('a', 'b')`.
619
+
620
+ ### 11.3 C2 Well-foundedness
621
+
622
+ No step MAY depend on itself through the uses of steps.
623
+
624
+ ### 11.4 C3 Justification
625
+
626
+ `By` MUST be one of the forms of Section 10.3. A `'builtin'` step MUST have
627
+ no bindings and no uses and a goal that is a primitive; an `'absent'` or
628
+ `'collected'` step MUST have no bindings and no uses and a goal that is a
629
+ negation or a `findall`, respectively.
630
+
631
+ ### 11.5 C4 Coverage
632
+
633
+ Each conjunct of each claim MUST have a step. Each use, and each conjunct of
634
+ a use, MUST have a step or be identical to an instance of a fact of the
635
+ program. A document without claims is valid and certifies nothing.
636
+
637
+ ### 11.6 C5 Re-decision
638
+
639
+ A `'builtin'` step's goal, solved as a primitive with no prior bindings, MUST
640
+ succeed without binding anything. A `'control'` step MUST have no bindings,
641
+ and its uses MUST be identical, in order, to the conjuncts of the argument of
642
+ `call` or `once`, or of one side of a disjunction. When trusted boundaries are
643
+ forbidden ("strict"), each `'absent'` or `'collected'` step fails C5.
644
+
645
+ ### 11.7 C6 Boundary consistency
646
+
647
+ A trusted boundary cannot be proved, but the evidence at hand can refute it.
648
+ The evidence for a goal is: when the goal is a ground primitive, the goal
649
+ itself if it holds; when it is a control, none, and the boundary is left
650
+ undecided; otherwise the program's facts and the goals of the document's
651
+ steps with the same name and arity.
652
+
653
+ - An absence `not(G)` is decided when `G` is a single goal, or a ground
654
+ conjunction, whose every goal has evidence. It fails C6 when every goal of
655
+ `G` unifies with some of its evidence; the anonymous variables of `G`
656
+ unify with anything.
657
+ - A collection `findall(T, G, L)` fails C6 when `L` is not a list, and is
658
+ decided when `G` is a single goal with evidence. It fails C6 when an
659
+ instance of `T` for some evidence of `G` unifies with no element of `L`.
660
+
661
+ A boundary that is not refuted remains an obligation (Section 12).
662
+
663
+ ### 11.8 C7 Relevance
664
+
665
+ When goals were given and no claim is `'false'`, the questions are the goals.
666
+ Otherwise the questions are, for each forward rule, each head other than
667
+ `'true'`, and the rule's body as a conjunction when one of its heads is
668
+ `'true'` and no claim is `'false'`. Each claim MUST be an instance of a
669
+ question. Each step MUST be reachable from a conjunct of a claim through the
670
+ conjuncts of uses.
671
+
672
+ ### 11.9 Counts and validity
673
+
674
+ | Condition | Covered |
675
+ | --- | --- |
676
+ | C1 resolution | `clause` steps that passed C1 |
677
+ | C2 well_founded | steps |
678
+ | C3 justification | steps |
679
+ | C4 coverage | claims plus uses |
680
+ | C5 re_decision | `'builtin'` and `'control'` steps that passed C5 |
681
+ | C6 boundary_consistency | boundaries decided |
682
+ | C7 relevance | claims plus steps |
683
+
684
+ A check also counts the **steps** it read, the **claims**, the `clause` steps
685
+ **verified** by C1, the `'builtin'` steps **recomputed** by C5, the
686
+ `'control'` steps **composed** by C5, and the `'absent'` and `'collected'`
687
+ steps **trusted**.
688
+
689
+ A proof is **valid** when no condition failed. A valid proof with trusted
690
+ boundaries is valid *conditional on* them.
691
+
692
+ ### 11.10 What a valid proof establishes
693
+
694
+ A valid proof establishes that each of its claims follows from the program
695
+ by the recorded steps, given its trusted boundaries. It does not establish
696
+ that the claims are all the conclusions of the program, that the program
697
+ derives no `'false'`, or that the program is the one intended: a proof MAY
698
+ leave conclusions out, and a run's own proof holds exactly its conclusions.
699
+
700
+ ## 12. Check Reports
701
+
702
+ A check report is a document (Section 9) holding, in this order, one fact per
703
+ line:
704
+
705
+ 1. `condition(Id, Name, Outcome, Covered)` for C1 to C7, where `Outcome` is
706
+ `'ok'` or `failed(N)`, `N` the number of that condition's failures;
707
+ 2. `failure(Condition, Subject, Detail)` per failure, where `Subject` is the
708
+ term concerned or `'proof_document'`, and `Detail` an atom;
709
+ 3. `obligation(Kind, 'theory_scoped', Goal)` per trusted boundary, in step
710
+ order, where `Kind` is `'absent'` or `'collected'`;
711
+ 4. `steps(N)`, `verified(N)`, `recomputed(N)`, `composed(N)`, `trusted(N)`,
712
+ `claims(N)`, the counts of Section 11.9;
713
+ 5. `verdict(V)`, where `V` is `failed(N)` when `N` failures were recorded,
714
+ otherwise `'checked_with_obligations'` when there are obligations,
715
+ otherwise `'checked'`.
716
+
717
+ Failures are listed in the order they are found: those of reading the
718
+ document (Section 11.1), in document order; C4 for each claim, in claim
719
+ order; then for each step, in document order, C4 for its uses and the C1, C3
720
+ or C5 failure of its justification; C6 for each boundary, in step order; C7
721
+ for each claim, then for each step; and C2.
722
+
723
+ `Detail` is a short human-readable text that names what failed, often with
724
+ the canonical text of a term; it is informative, and implementations MAY word
725
+ it differently. eyecode's details are, by condition:
726
+
727
+ | Condition | Details |
728
+ | --- | --- |
729
+ | C1 | `clause display differs from source`, `unknown clause ...`, `not an instance of source clause N: ...` |
730
+ | C2 | `cyclic derivation at ...` |
731
+ | C3 | the reader's error, `step bindings must be an object and uses an array`, `duplicate justification for ...`, `invalid builtin justification`, `trusted boundaries cannot have bindings or uses`, `unknown justification ...` |
732
+ | C4 | `unjustified claim ...`, `unjustified use ...` |
733
+ | C5 | `primitive disagrees: ...`, `control step does not follow from its uses: ...`, `trusted boundary forbidden: absent` or `collected` |
734
+ | C6 | `absence contradicted by evidence: ...`, `collected result is not a proper list: ...`, `collection misses ...: ...` |
735
+ | C7 | `claim answers no goal: ...`, `step serves no claim: ...` |
736
+
737
+ The variables of each fact are renamed `A`, `B`, ..., `Z`, `A1`, ... in order
738
+ of first occurrence. A report is ordinary data: `facts_from` (Section 4.2)
739
+ states it as facts.
740
+
741
+ The JSON form of a report is an object with `valid` (boolean), `steps`,
742
+ `claims`, `verified`, `redecided` (the count `recomputed`), `composed`,
743
+ `uses` (the number of uses of all steps, integers), `trusted`
744
+ (a list of `{kind, conclusion}`), `failures` (a list of
745
+ `{condition, detail, conclusion?}`) and `conditions` (a list of
746
+ `{id, name, covered, failed}`), where `conclusion` is a canonical text.
747
+
748
+ ## 13. Unused Clauses
749
+
750
+ A clause is **unused** when no conclusion's recorded derivation cites it,
751
+ unless a negation or collection in the proof could consult it and running the
752
+ program without it changes the conclusions or the halt code, or fails. The clauses a
753
+ negation or collection could consult are those whose heads have the name and
754
+ arity of a goal it reaches through the program's bodies.
755
+
756
+ Unused clauses are reported one per line, in clause order, as
757
+ `unused(line(L), Display)`, where `L` is the clause's line (Section 4.2) and
758
+ `Display` as in Section 10.2.
759
+
760
+ "Unused" is relative to the recorded derivations, which are the first ones
761
+ found (Section 7.7). A clause that only offers a second derivation of a
762
+ conclusion, such as a duplicate rule, is unused, though leaving out the
763
+ clause that offers the first one would make it used; leaving out several
764
+ unused clauses together can therefore change the conclusions. A
765
+ `contradiction` rule that never fires changes no conclusion and is unused,
766
+ though it guards the program against data that would make it fire.
767
+
768
+ ## 14. Command Line
769
+
770
+ ```text
771
+ eyecode [OPTION ...] [FILE ...]
772
+ ```
773
+
774
+ | Option | Meaning |
775
+ | --- | --- |
776
+ | (none) | Load the files, or standard input, as one program and print its conclusions. |
777
+ | `--proof` | Print the proof document instead. |
778
+ | `--check-proof FILE` | Check the proof in `FILE` (`-` for standard input) against the program and print its report. |
779
+ | `--json` | With `--check-proof`, print the report as JSON. |
780
+ | `--goal GOAL` | Ask `GOAL`, read as in Section 9, where an array is a conjunction; MAY be repeated. With `--check-proof`, the goals the proof answers. |
781
+ | `--strict-proof` | With `--check-proof`, forbid trusted boundaries. |
782
+ | `--unused` | Print the unused clauses (Section 13). |
783
+ | `--stats` | Print reasoning statistics as JSON to standard error. |
784
+ | `--max-depth N`, `--max-iterations N`, `--max-inferences N` | The bounds of Section 7.3; `N` MUST be a positive integer. |
785
+ | `--version`, `--help` | Print the version, or the usage. |
786
+
787
+ `--check-proof` MUST NOT be combined with `--proof`, nor `--unused` with
788
+ either, and `--json` and `--strict-proof` need `--check-proof`. A program
789
+ text that has a line starting with `step(` is a proof document; given one as
790
+ a program, the command line MUST say how to check it instead.
791
+
792
+ | Exit code | Meaning |
793
+ | --- | --- |
794
+ | 0 | Success, including a check that found the proof valid. |
795
+ | 1 | An error, printed to standard error as `eyecode: message`. |
796
+ | 2 | A check that found the proof not valid; the report is printed as usual. |
797
+ | 65 | The run halted (Section 7.5). |
798
+
799
+ ## 15. Security Considerations
800
+
801
+ A **program** is JavaScript code and runs with the privileges of whoever runs
802
+ it; only programs from trusted sources should be run. Reasoning itself calls
803
+ no code of the program: once stated, clauses are terms.
804
+
805
+ A **document** (conclusions, proofs, reports, `facts_from` input and goals)
806
+ is untrusted data. It MUST NOT be executed. The reader of Section 9 accepts
807
+ literals, names, calls of a plain name and array and object literals, so no
808
+ document can run code, import modules or reach properties. Checking a proof
809
+ from a third party is therefore safe in the sense that it runs none of the
810
+ third party's code.
811
+
812
+ Reasoning and checking consume time and memory. The bounds of Section 7.3,
813
+ the limit on powers and shifts in Section 6 and the limit on `functor`
814
+ arities in Section 5.2 bound some of this; a deployment that checks untrusted
815
+ proofs SHOULD additionally bound document size, nesting depth and running
816
+ time.
817
+
818
+ A valid proof establishes that its claims follow from the program supplied
819
+ to the checker (Section 11.10). It does not establish that the program is
820
+ correct or that the claims are all its conclusions, and a proof with
821
+ obligations holds only conditional on them.
822
+
823
+ ## 16. Conformance
824
+
825
+ A conforming **reasoner** implements Sections 3 to 10, produces
826
+ conclusions and proof documents in the canonical text, and checks every proof
827
+ it produces as Section 11 describes. A conforming **checker** implements
828
+ Sections 9, 11 and 12 and does not depend on a reasoner. For the same
829
+ program, a conforming reasoner and checker MUST produce the same
830
+ conclusions, proof documents and reports as eyecode 0.1.3, byte for byte,
831
+ except for the `Detail` texts of failures (Section 12), the internal names of
832
+ variables where Section 3 says so, and where the host's floating-point
833
+ library functions (`exp`, `log`, the trigonometric and hyperbolic functions,
834
+ `pow` of floats) differ in the last digit.
835
+
836
+ The conformance suite in the repository's `conformance/` directory tests an
837
+ implementation against this document through its command line, case by case,
838
+ each case naming the sections it tests; `conformance/README.md` describes how
839
+ to run it against any implementation. The repository's examples, with their
840
+ saved conclusions (`examples/output/`), proofs (`examples/proof/`) and reports
841
+ (`examples/check/`), test the same on larger programs.
842
+
843
+ ---
844
+
845
+ ## Appendix A. Document Grammar
846
+
847
+ The documents of Sections 9 to 12 use this subset of JavaScript's expression
848
+ grammar, in the ABNF style of RFC 5234, with spaces, tabs and comments
849
+ between tokens allowed, and line breaks too inside brackets.
850
+
851
+ ```abnf
852
+ document = *( line LF ) [ line ]
853
+ line = [ expression *( ";" expression ) [ ";" ] ]
854
+ expression = string / number / "-" number / name / call / array / object
855
+ / "(" expression ")"
856
+ call = name "(" [ expression *( "," expression ) [ "," ] ] ")"
857
+ array = "[" [ items ] "]"
858
+ items = expression *( "," expression ) [ "," "..." expression ] [ "," ]
859
+ / "..." expression [ "," ]
860
+ object = "{" [ pair *( "," pair ) [ "," ] ] "}"
861
+ pair = ( name / string ) ":" expression
862
+ string = "'" *<character or escape> "'" / DQUOTE *<character or escape> DQUOTE
863
+ number = 1*DIGIT [ "n" ] / float
864
+ float = ( 1*DIGIT "." *DIGIT / "." 1*DIGIT ) [ exponent ] / 1*DIGIT exponent
865
+ exponent = ( "e" / "E" ) [ "+" / "-" ] 1*DIGIT
866
+ name = ( ALPHA / "_" ) *( ALPHA / DIGIT / "_" ) ; not a reserved word
867
+ ```
868
+
869
+ An integer literal other than `0` MUST NOT begin with `0`.
870
+
871
+ ## Appendix B. Example
872
+
873
+ The program `socrates.js`:
874
+
875
+ ```js
876
+ fact(type('socrates', 'human'))
877
+ fact(subclass_of('human', 'mortal'))
878
+ implies([type(S, A), subclass_of(A, B)], type(S, B))
879
+ query(type(X, Y))
880
+ ```
881
+
882
+ Its conclusions:
883
+
884
+ ```js
885
+ type('socrates', 'mortal')
886
+ type('socrates', 'human')
887
+ ```
888
+
889
+ Its proof document (Section 10):
890
+
891
+ ```js
892
+ type('socrates', 'mortal')
893
+ type('socrates', 'human')
894
+
895
+ clause(1, fact(type('socrates', 'human')))
896
+ clause(2, fact(subclass_of('human', 'mortal')))
897
+ clause(3, implies([type(S, A), subclass_of(A, B)], type(S, B)))
898
+
899
+ step(type('socrates', 'mortal'), clause(3), {S: 'socrates', A: 'human', B: 'mortal'}, [type('socrates', 'human'), subclass_of('human', 'mortal')])
900
+ step(type('socrates', 'human'), clause(1), {}, [])
901
+ step(subclass_of('human', 'mortal'), clause(2), {}, [])
902
+ ```
903
+
904
+ Its check report (Section 12):
905
+
906
+ ```js
907
+ condition('C1', 'resolution', 'ok', 3)
908
+ condition('C2', 'well_founded', 'ok', 3)
909
+ condition('C3', 'justification', 'ok', 3)
910
+ condition('C4', 'coverage', 'ok', 4)
911
+ condition('C5', 're_decision', 'ok', 0)
912
+ condition('C6', 'boundary_consistency', 'ok', 0)
913
+ condition('C7', 'relevance', 'ok', 5)
914
+ steps(3)
915
+ verified(3)
916
+ recomputed(0)
917
+ composed(0)
918
+ trusted(0)
919
+ claims(2)
920
+ verdict('checked')
921
+ ```