eyeprolog 1.3.52 → 1.3.53

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/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.3.52",
6
+ "version": "1.3.53",
7
7
  "description": "EyeProlog turns facts and rules into answers and proofs.",
8
8
  "type": "module",
9
9
  "main": "./index.js",
@@ -104,9 +104,17 @@ function evaluateOperation(term, args, options = {}) {
104
104
  if (options.isoStrict === true && ['truncate', 'round', 'ceiling', 'floor'].includes(name) && args[0].integer) {
105
105
  throw new PrologError('type_error(float)', numericTerm(args[0]));
106
106
  }
107
- const a = Number(args[0].value);
108
107
  if (name === 'abs' && args[0].integer) return { integer: true, value: args[0].value < 0n ? -args[0].value : args[0].value };
109
108
  if (name === 'sign' && args[0].integer) return { integer: true, value: args[0].value < 0n ? -1n : args[0].value > 0n ? 1n : 0n };
109
+ const a = Number(args[0].value);
110
+ // The int-exp -> float templates first apply the processor's I->F
111
+ // conversion. With unbounded integers that conversion can overflow even
112
+ // though the integer itself is representable. Do not let a host math
113
+ // function observe +/-Infinity and turn the required float-overflow into
114
+ // a different result (for example atan(Huge) = pi/2).
115
+ if (options.isoStrict === true && args[0].integer && !Number.isFinite(a)) {
116
+ throw new PrologError('evaluation_error(float_overflow)');
117
+ }
110
118
  if (name === 'truncate' || name === 'round' || name === 'ceiling' || name === 'floor') {
111
119
  const fn = name === 'truncate' ? Math.trunc : name === 'round' ? Math.round : name === 'ceiling' ? Math.ceil : Math.floor;
112
120
  return { integer: true, value: BigInt(fn(a)) };
@@ -120,6 +128,13 @@ function evaluateOperation(term, args, options = {}) {
120
128
  const value = fn(a);
121
129
  if (Number.isNaN(value) || (name === 'log' && a === 0)) throw new PrologError('evaluation_error(undefined)');
122
130
  if (!Number.isFinite(value)) throw new PrologError('evaluation_error(float_overflow)');
131
+ // Unlike the implementation-defined resultF choice for ordinary floating
132
+ // arithmetic, exp/1 has an explicit exceptional condition when its
133
+ // mathematical non-zero result is too small to represent. Math.exp()
134
+ // signals that boundary by rounding the positive result to zero.
135
+ if (options.isoStrict === true && name === 'exp' && value === 0) {
136
+ throw new PrologError('evaluation_error(underflow)');
137
+ }
123
138
  return { integer: false, value };
124
139
  }
125
140
  if (arity !== 2) throw new PrologError('type_error(evaluable)', compound('/', [atom(name), numberTerm(arity)]));
@@ -158,6 +173,28 @@ function evaluateOperation(term, args, options = {}) {
158
173
  if (name === '<<') return { integer: true, value: integerResource(() => a << b) };
159
174
  if (name === '>>') return { integer: true, value: integerResource(() => a >> b) };
160
175
  }
176
+ // Power has prescribed exceptional conditions that depend on the evaluated
177
+ // operand values/types and therefore precede any I->F conversion needed by
178
+ // the selected floating template. Checking these first matters with
179
+ // unbounded integers: conversion overflow must not hide an already-satisfied
180
+ // undefined-power condition.
181
+ const aNegative = args[0].integer ? a < 0n : a < 0;
182
+ const aZero = args[0].integer ? a === 0n : a === 0;
183
+ const bNegative = args[1].integer ? b < 0n : b < 0;
184
+ if (options.isoStrict === true && name === '**' && aNegative && !args[1].integer) {
185
+ // Corrigendum 3 corrects the operand name in 9.3.1.3(c): **/2 requires
186
+ // an integer-typed exponent for a negative base. A float such as 2.0 is
187
+ // still not an integer value of the required type here.
188
+ throw new PrologError('evaluation_error(undefined)');
189
+ }
190
+ if (options.isoStrict === true && name === '^' && aNegative && !args[1].integer && !Number.isInteger(b)) {
191
+ // Corrigendum 2 ^/2 additionally accepts a float with an integer value.
192
+ throw new PrologError('evaluation_error(undefined)');
193
+ }
194
+ if ((name === '**' || name === '^') && aZero && bNegative) {
195
+ throw new PrologError('evaluation_error(undefined)');
196
+ }
197
+
161
198
  const x = Number(a), y = Number(b);
162
199
  if ((!Number.isFinite(x) || !Number.isFinite(y)) && name !== 'max' && name !== 'min') {
163
200
  throw new PrologError('evaluation_error(float_overflow)');
@@ -173,11 +210,6 @@ function evaluateOperation(term, args, options = {}) {
173
210
  if (x === 0 && y === 0) throw new PrologError('evaluation_error(undefined)');
174
211
  value = Math.atan2(x, y);
175
212
  }
176
- else if ((name === '**' || name === '^') && x === 0 && y < 0) {
177
- // 9.3.1.3(d) and Cor.2 9.3.10.3(d): zero to a negative power is
178
- // undefined, not floating-point overflow.
179
- throw new PrologError('evaluation_error(undefined)');
180
- }
181
213
  else if (name === '+') value = x + y;
182
214
  else if (name === '-') value = x - y;
183
215
  else if (name === '*') value = x * y;
@@ -186,6 +218,14 @@ function evaluateOperation(term, args, options = {}) {
186
218
  else throw new PrologError('type_error(evaluable)', compound('/', [atom(name), numberTerm(arity)]));
187
219
  if (Number.isNaN(value)) throw new PrologError('evaluation_error(undefined)');
188
220
  if (!Number.isFinite(value)) throw new PrologError('evaluation_error(float_overflow)');
221
+ // Part 1 **/2 and Corrigendum 2 ^/2 prescribe underflow when a
222
+ // mathematically non-zero floating power is too small. A non-zero finite
223
+ // base cannot have an exact zero power result, so a host result of +/-0 is
224
+ // the observable underflow boundary. Zero raised to a positive power remains
225
+ // the ordinary exact zero case.
226
+ if (options.isoStrict === true && (name === '**' || name === '^') && value === 0 && x !== 0) {
227
+ throw new PrologError('evaluation_error(underflow)');
228
+ }
189
229
  return { integer: false, value };
190
230
  }
191
231
  export function arithmeticValueTerm(value) {
@@ -36,12 +36,12 @@ error-ordering alternative to an individual executable assertion.
36
36
  | 7.5-7.6 — database and term/clause conversion | audit | Dynamic database and logical-update-view suites. Strict mode restores Part 1 private-static/public-dynamic `clause/2` access; focused strict checks now cover `current_predicate/1`, `clause/2`, `asserta/1`, `assertz/1`, `retract/1`, Corrigendum 2 `retractall/1`, and `abolish/1` errors plus empty-procedure lifetime. Runtime protection includes the solver-native conjunction control construct `','/2` and, following STC #56's accepted-direction action item, the source syntax functors `(:-)/1-2` for database modification/private access while leaving their call behavior distinct. The remaining clause-conversion shall-by-shall mapping is still open. |
37
37
  | 7.7 — execution and backtracking | audit | Control/search suites. Strict mode disables EyeProlog automatic tabling, cycle guards, and recursive numeric shortcuts so core execution uses ordinary clause selection/backtracking. |
38
38
  | 7.8 — control constructs and exceptions | audit | call, cut, conjunction, disjunction (including failed branches after callee-local cuts), if-then, catch/throw, renamed-copy tests. |
39
- | 7.9 — expression evaluation | audit | Arithmetic/evaluation/error suites, including Corrigenda. Strict mode now also pins direct-variable precedence, arithmetic operand type errors, float-only rounding conversions, zero-to-negative-power undefined errors, and the Part 1 mixed integer/float comparison conversion rule. Unbounded integer powers/shifts no longer leak host `RangeError`; finite-host exhaustion is normalized to `resource_error(memory)` in line with the Part 1 resource-error note and STC #21. Exceptional-value/error-precedence mapping remains to be exhaustively enumerated. |
39
+ | 7.9 — expression evaluation | audit | Arithmetic/evaluation/error suites, including Corrigenda. Strict mode now pins direct-variable precedence, arithmetic operand type errors, float-only rounding conversions, the Part 1 mixed integer/float comparison conversion rule, I->F overflow before floating evaluable functors (STC #42), explicit `exp/1`/power underflow, and prescribed negative/zero power errors before later conversion overflow. Unbounded integer powers/shifts no longer leak host `RangeError`; finite-host exhaustion is normalized to `resource_error(memory)` in line with the Part 1 resource-error note and STC #21. The remaining exceptional-value/error-precedence rows are still being exhaustively enumerated. |
40
40
  | 7.10 — input/output concepts | audit | Stream, character/byte I/O, read/write options, operator-sensitive write-back, and Corrigendum 3 writer cases. The audit now also covers write-mode creation/truncation, append creation, repositioned overwrite, flushing, EOF actions, close/current-stream handling, strict stream-position terms, stream-property validation, stream-term requirements, text-vs-binary permission errors, and the prescribed `alias(A)` culprit for `open/4` alias collisions. The full option/mode cross-product is still being mapped. |
41
41
  | 7.11 — flags | covered | The complete Part 1 flag set, selected defaults, standard value domains, changeability, `current_prolog_flag/2`, and `set_prolog_flag/2` error behavior have dedicated strict tests. EyeProlog selects `bounded=false` and `integer_rounding_function=toward_zero`; valid alternative values of those fixed flags reach `permission_error(modify,flag,...)`, while `max_integer` and `min_integer` have no current value. Strict mode excludes the EyeProlog `occurs_check` extension. |
42
42
  | 7.12 — errors | audit | ISO `error(Error, Context)` envelope, type/domain/permission/representation/evaluation/syntax/resource families and focused error cases. Exact ISO 8.14.1-8.14.4 error precedence is covered for `read_term/3`, `write_term/3`, `op/3`, and `current_op/3`; the continuing audit has corrected additional 8.11-8.13 stream/character/byte errors (including the complete `alias(A)` culprit for `open/4` alias collisions), Corrigendum 2 `keysort/2` errors, atomic-conversion list-shape precedence, `arg/3`, `atom_concat/3`, `sub_atom/5`, `char_conversion/2`, runtime control-construct/database protection, arithmetic culprit/precedence reporting, and host-resource normalization for unbounded term/integer operations. A complete one-row-per-prescribed-error ordering map remains open. |
43
43
  | 8.2-8.17 — built-in predicates | audit | Predicate-family coverage is mapped in ISO-MATRIX.md; Corrigendum 2 additions (`subsumes_term/2`, `term_variables/2`, `call/2..8`, `false/0`) are in the strict registry. The audit now includes corrected `keysort/2` variable/non-pair errors, stricter 8.11-8.13 stream and character/byte modes/errors, the 8.14 option/error-order subfamily, closed 8.17 flags, additional prescribed precedence for `arg/3`, `atom_concat/3`, `sub_atom/5`, number/atom list conversions, and `char_conversion/2`, plus finite-host resource handling for unbounded `functor/3` construction. The remaining mode/error matrix is not yet one-row-per-standard-row. |
44
- | Clause 9 — evaluable functors | audit | Integer/float/rounding/transcendental/bitwise suites and corrigendum cases. Strict mode excludes the EyeProlog-only evaluable atom `e`, retains Corrigendum 2 arithmetic additions, reports unknown zero-arity evaluables with the required `F/0` culprit shape, enforces the Part 1 numeric/integer operand errors and float-only rounding modes, and uses the Part 1 integer-to-float conversion rule for mixed arithmetic comparisons. Normal mode retains EyeProlog's exact mixed-type comparison extension. Unbounded BigInt resource exhaustion is translated into the Prolog error model rather than leaking host exceptions. Host floating-point representation choices remain documented implementation-defined behavior; exhaustive exceptional-value precedence remains open. |
44
+ | Clause 9 — evaluable functors | audit | Integer/float/rounding/transcendental/bitwise suites and corrigendum cases. Strict mode excludes the EyeProlog-only evaluable atom `e`, retains Corrigendum 2 arithmetic additions, reports unknown zero-arity evaluables with the required `F/0` culprit shape, enforces the Part 1 numeric/integer operand errors and float-only rounding modes, performs I->F conversion before floating functors (including overflow), reports the explicit `exp/1`, `**/2`, and Corrigendum 2 `^/2` underflow conditions, preserves the power-specific undefined conditions ahead of conversion overflow, and uses the Part 1 integer-to-float rule for mixed arithmetic comparisons. Normal mode retains EyeProlog's exact mixed-type comparison and round-to-zero arithmetic behavior as extensions. Unbounded BigInt resource exhaustion is translated into the Prolog error model rather than leaking host exceptions. Host floating-point representation choices remain documented implementation-defined behavior; the remaining exceptional-value rows are still under audit. |
45
45
  | Corrigendum 1 | covered | Double-quoted atom/operator-priority corrections have dedicated cases. |
46
46
  | Corrigendum 2 | covered | Added predicates/functors, catch corrections, bar/operator and uninstantiation corrections have dedicated cases. |
47
47
  | Corrigendum 3 | covered | Writer options, `variable_names/1`, canonical list output and negative-power corrections have dedicated cases. |
@@ -137,6 +137,19 @@ its exact cross-type comparison as an extension. Dedicated strict regressions
137
137
  cover these distinctions without changing the normal-profile arithmetic error
138
138
  contract.
139
139
 
140
+ A further Clause 9 pass closes the floating conversion and exceptional-value
141
+ boundary exposed by unbounded integers. Strict floating evaluable functors now
142
+ perform the required integer-to-float conversion before invoking the host math
143
+ operation, so an integer outside the selected finite binary64 range reports
144
+ `evaluation_error(float_overflow)` rather than producing a secondary host-math
145
+ result. The explicit underflow clauses for `exp/1`, Part 1 `**/2`, and
146
+ Corrigendum 2 `^/2` are enforced even though EyeProlog retains the
147
+ implementation-defined `round(x)` choice for generic `resultF` arithmetic. The
148
+ power audit also preserves the specified negative-base and zero/negative
149
+ exception conditions before any later I->F overflow, including Corrigendum 3's
150
+ correction to the `**/2` operand wording and Corrigendum 2's distinct rule that
151
+ `^/2` may accept an integer-valued float exponent.
152
+
140
153
  ## Post-Corrigendum STC cross-check
141
154
 
142
155
  The public WG17 STC draft is tracked as useful defect-discovery material, but it
@@ -73,7 +73,7 @@ Status values are:
73
73
  | 8.17.3 | Other effects of `halt/0` | Terminates EyeProlog execution and returns host/process status `0`; it produces no Prolog solution. | **defined** — `HaltSignal`, `haltBuiltin()`, CLI/runner handling. |
74
74
  | 8.17.4 | Meaning/effects of `halt(Status)` | Integer `Status` is converted to the host process/runner halt code; it produces no Prolog solution. | **defined** — `haltBuiltin()`, `src/execute.js`, `src/cli.js`. |
75
75
  | 9.1.4.1 | Floating-point rounding function `rndF` | Floating values and operations use ECMAScript `Number` (IEEE-754 binary64) and the host's specified binary64 arithmetic/conversions. | **defined** — `src/iso-arithmetic.js`, `src/number-value.js`. |
76
- | 9.1.4.2 | Floating-point result function, including tiny non-zero arithmetic results | EyeProlog chooses `round(x)` rather than the exceptional value `underflow`. ECMAScript binary64 arithmetic therefore preserves a representable subnormal result and rounds a still-smaller result to `0.0`, consistently with float-token and `number_chars/2` input. | **defined** — arithmetic evaluation in `src/iso-arithmetic.js` and parser/number conversion; executable issue-56 regression below. |
76
+ | 9.1.4.2 | Floating-point result function for operations whose result is governed only by `resultF` | EyeProlog chooses `round(x)` rather than the optional exceptional value `underflow`. ECMAScript binary64 arithmetic therefore preserves a representable subnormal result and rounds a still-smaller generic arithmetic result to `0.0`, consistently with float-token and `number_chars/2` input. This implementation-defined choice does not suppress the explicit mandatory underflow conditions stated separately for Part 1 `**/2`, `exp/1`, and Corrigendum 2 `^/2`. | **defined** — arithmetic evaluation in `src/iso-arithmetic.js` and parser/number conversion; strict exceptional-value regressions. |
77
77
  | 9.1.4.3 | Approximate-addition function | ECMAScript binary64 addition is used; subtraction is implemented through the corresponding host operation and all finite results remain binary64 values. | **defined** — arithmetic evaluation in `src/iso-arithmetic.js`. |
78
78
  | 9.4 | Representation of negative integers for bitwise operations | BigInt's unbounded signed binary semantics are used, equivalent to an infinite two's-complement sign extension for bitwise operations. | **defined** — `src/iso-arithmetic.js` BigInt bitwise operators. |
79
79
  | 9.4.1 | Right shift of negative integers and unusual shift counts | `>>` is arithmetic/sign-propagating. A negative count reverses direction according to JavaScript BigInt shift semantics; there is no finite integer bit-size ceiling in the Prolog model. | **defined** — `a >> b` in `src/iso-arithmetic.js`. |
@@ -86,15 +86,20 @@ Status values are:
86
86
  ### Issue #56: one underflow policy
87
87
 
88
88
  Clause 9.1.4.2 permits the processor to choose `round(x)` or the exceptional
89
- value `underflow` for a tiny non-zero arithmetic result. EyeProlog chooses
90
- `round(x)`. Because its floating-point profile is ECMAScript IEEE-754 binary64,
91
- representable subnormal values remain non-zero and smaller results round to
89
+ value `underflow` for a tiny non-zero result when an operation is governed by
90
+ the generic floating result function. EyeProlog chooses `round(x)`. Because its
91
+ floating-point profile is ECMAScript IEEE-754 binary64, representable
92
+ subnormal values remain non-zero and still-smaller generic results round to
92
93
  `0.0`. Float-token and `number_chars/2` input use the same finite-double
93
- rounding policy, so the same mathematical magnitude is no longer accepted as
94
- `0.0` on input while rejected as an arithmetic result.
95
-
96
- The regression suite checks both arithmetic and token input, and the existing
97
- `stc/float_underflow_input` conformance case covers the related input conversion.
94
+ rounding policy.
95
+
96
+ That generic implementation-defined choice is distinct from evaluable functors
97
+ whose own error clauses prescribe underflow. In strict mode, `exp/1`, Part 1
98
+ `**/2`, and Corrigendum 2 `^/2` therefore raise
99
+ `evaluation_error(underflow)` when their mathematical non-zero result falls
100
+ below the representable range and the host would otherwise round it to zero.
101
+ The regression suite pins both sides of this boundary, while
102
+ `stc/float_underflow_input` covers the related input conversion policy.
98
103
 
99
104
  ## Implementation-specific features required to be documented by 5.4
100
105
 
@@ -18,7 +18,7 @@ compliance audit and the remaining work before a full conformance claim.
18
18
  | 8.15 logic and control | negation, once, repeat, `call/2` through `call/8`, `false/0` | `logtalk_once`, `corrigenda_call_closure`, `false_builtin`, plus strict Corrigendum 2 resulting-goal `max_arity` error coverage |
19
19
  | 8.16 atomic processing | atoms, characters, codes and number conversion with prescribed errors | `atomic_term_processing`, focused forward/reverse cases, parenthesized-number rejection, Logtalk-derived error cases, strict Corrigendum 2 partial/improper-list precedence for atom/number conversions, and prescribed `atom_concat/3` / `sub_atom/5` ordering checks |
20
20
  | 8.17 flags and hooks | complete required Part 1 flag set, selected defaults, standard value domains/changeability, halt and character conversion | `exceptions_and_flags`, `remaining_builtins_and_directives`, flag error cases, strict `char_conversion/2` precedence, and the complete strict flag audit in `run-iso-strict.mjs` |
21
- | Clause 9 evaluable functors | integer, float, rounding, transcendental and bitwise operations | `arithmetic`, `corrigenda_arithmetic`, `corrigenda_atan2_zero`, `corrigenda_integer_negative_power`, strict exclusion of the normal-mode `e` evaluable extension, zero-arity unknown-evaluable checks, prescribed operand/type and negative-power errors, float-only rounding modes, Part 1 mixed integer/float comparison conversion, and resource-error normalization for finite-host exhaustion of unbounded integer operations |
21
+ | Clause 9 evaluable functors | integer, float, rounding, transcendental and bitwise operations | `arithmetic`, `corrigenda_arithmetic`, `corrigenda_atan2_zero`, `corrigenda_integer_negative_power`, strict exclusion of the normal-mode `e` evaluable extension, zero-arity unknown-evaluable checks, prescribed operand/type and power-error precedence, float-only rounding modes, I->F overflow before floating functors, explicit `exp/1`/`**/2`/`^/2` underflow, Part 1 mixed integer/float comparison conversion, and resource-error normalization for finite-host exhaustion of unbounded integer operations |
22
22
  | Module compatibility profile (related to ISO/IEC 13211-2 and later WG17 amendment work) | module declarations, exports, imports, qualification, meta-predicate context | `modules/qualified_call`, `modules/selective_library_import`, `dcg_module_nonterminal_indicator` |
23
23
  | Part 3-oriented DCG compatibility profile | `-->`, terminal and partial sequences, grammar control constructs, semicontexts, nonterminal indicators, modules, `phrase/2-3`, steadfastness and errors | `dcg_terminals_and_remainder`, `dcg_control_constructs`, `dcg_partial_sequences`, `dcg_phrase_steadfastness`, `dcg_dynamic_nonterminal_indicator`, `logtalk_dcg_phrase_identity`, `logtalk_dcg_semicontexts`, DCG error and precedence cases |
24
24
 
@@ -33,7 +33,8 @@ clause-by-clause in [ISO-IMPLEMENTATION-DEFINED.md](ISO-IMPLEMENTATION-DEFINED.m
33
33
  with *The Art of EyeProlog* remaining the implementation reference. In
34
34
  particular, the index records the unbounded integer model, `double_quotes=chars`,
35
35
  `//` rounding toward zero, the ECMAScript binary64 float policy (including the
36
- 9.1.4.2 choice to round tiny arithmetic results rather than raise underflow),
36
+ 9.1.4.2 choice to round generic tiny results while retaining explicit
37
+ functor-specific underflow errors),
37
38
  stream/character decisions, and the normal-profile extension boundary.
38
39
 
39
40
  This is an executable conformance/compatibility matrix, not a certification issued by an
@@ -17,14 +17,18 @@ regressions.
17
17
 
18
18
  | STC item | Topic | EyeProlog evidence / finding |
19
19
  | --- | --- | --- |
20
+ | [#17](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#17) | expression-error overlap | The strict suite pins both `X is 1/0+_` and `X is _+1/0` to `instantiation_error`, so the direct-variable rule is not masked by implementation evaluation order or a zero-divisor on the other operand. |
20
21
  | [#18](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#18) | `eof_action(error)` | Stream regressions verify the first EOF observation yields the EOF value and a subsequent read with `eof_action(error)` raises `permission_error(input,past_end_of_stream,...)`; `eof_code` and `reset` remain distinct. |
21
22
  | [#21](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#21) | unbounded-integer resource exhaustion | The strict suite now prevents host `RangeError` leakage from oversized integer shifts/powers and reports `resource_error(memory)`, consistent with the Part 1 resource-error note and the STC correction proposal. The same principle is used when unbounded `functor/3` construction exhausts a finite host resource. |
22
23
  | [#27](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#27)-[#29](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#29) | overlapping character/code/byte stream errors | Existing stream tests plus strict probes preserve argument validation before later stream-state errors where the published error clauses require it; the STC examples with an open alias produce the stated instantiation/type errors. |
24
+ | [#32](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#32) | `number_chars/2` declarative/procedural wording | The strict suite follows the published procedural number-syntax path: `number_chars(N,['0','1'])` succeeds with `N = 1`. This records the executable behavior without treating the draft wording proposal as a new normative clause. |
23
25
  | [#37](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#37) | `clause/2` variable identity | `stc/clause_variable_identity` verifies sharing between head and body is preserved. |
24
26
  | [#39](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#39) | negative-number syntax | Covered extensively by the upstream-first WG17 syntax matrix; unary-minus read-back discrepancies found by that matrix were fixed in v1.3.27. |
25
27
  | [#40](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#40) | inexact float representation | EyeProlog uses the host IEEE-754 binary64 value and requires written floats to read back to that same value. Input underflow is covered by `stc/float_underflow_input`. |
26
- | [#42](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#42) | integer-to-float conversion for float functions | `stc/integer_to_float_evaluable` verifies an integer expression is accepted by `sin/1` and produces a float. |
28
+ | [#41](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#41) | preparation-time `op/3` ordering | A strict parser regression verifies an `op/3` directive affects following text and cannot retroactively make preceding text parse with the new operator. The same preparation machinery is used for `set_prolog_flag/2`. |
29
+ | [#42](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#42) | integer-to-float conversion for float functions | `stc/integer_to_float_evaluable` verifies an integer expression is accepted by `sin/1` and produces a float. The strict suite additionally verifies that an unbounded integer outside the finite binary64 range raises `evaluation_error(float_overflow)` during I->F conversion before `sin/1`, `cos/1`, `atan/1`, the Corrigendum 2 inverse/trigonometric additions, `exp/1`, `log/1`, `sqrt/1`, or `float/1` can observe a host infinity. |
27
30
  | [#44](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#44) | `char_code/2` error classification | Strict coverage distinguishes `type_error(integer,Code)` for a non-integer code from `representation_error(character_code)` for an integer outside the character-code set. |
31
+ | [#48](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#48) | `read_term/3` option wording with `variables([])` | The strict suite verifies `read_term(T,[variables([])])` on input `T.` has no solution because the actual variable list cannot unify with `[]`; this keeps the operational option semantics clear despite the draft's wording concern. |
28
32
  | [#49](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#49) | `read_term/3` and EOF | Covered by strict reader/conformance tests and the interactive-read regressions. |
29
33
  | [#50](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#50) | mixed integer/float arithmetic comparison | The STC-facing normal-profile case requires exact cross-type ordering and `max/2`/`min/2` use the same comparison. `--iso-strict` deliberately retains the published Part 1 integer-to-float comparison rule; the draft case is not silently substituted for that normative baseline. |
30
34
  | [#55](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#55) | integer rounding function | Existing flag conformance verifies `integer_rounding_function = toward_zero`. |
@@ -300,6 +300,50 @@ export function runIsoStrict(reporter = new TestReporter()) {
300
300
  }
301
301
  });
302
302
 
303
+ reporter.test('applies integer-to-float conversion before floating evaluable functors', () => {
304
+ const huge = `1${'0'.repeat(400)}`;
305
+ for (const functor of ['float', 'sin', 'cos', 'atan', 'asin', 'acos', 'tan', 'exp', 'log', 'sqrt']) {
306
+ equal(capture(() => run('', { isoStrict: true, goal: `X is ${functor}(${huge})` })).formal,
307
+ 'evaluation_error(float_overflow)', `${functor}/1 integer-to-float overflow`);
308
+ }
309
+ });
310
+
311
+ reporter.test('reports explicit transcendental and power underflow in strict mode', () => {
312
+ for (const [goal, label] of [
313
+ ['X is exp(-1000.0)', 'exp/1 underflow'],
314
+ ['X is 2.0 ** -1075.0', '**/2 underflow'],
315
+ ['X is 2.0 ^ -1075.0', 'Corrigendum 2 ^/2 underflow'],
316
+ ]) {
317
+ equal(capture(() => run('', { isoStrict: true, goal })).formal,
318
+ 'evaluation_error(underflow)', label);
319
+ }
320
+
321
+ equal(run('', { isoStrict: true, goal: 'X is 0.0 ** 2.0' }).stats.completed_goal_lists,
322
+ 1, 'exact zero power remains zero');
323
+ equal(run('', { isoStrict: true, goal: 'X is 4.9406564584124654e-324 * 0.5' }).stats.completed_goal_lists,
324
+ 1, 'generic resultF retains the selected round-to-zero policy');
325
+
326
+ // Keep these stricter exceptional conditions confined to --iso-strict.
327
+ equal(run('', { goal: 'X is exp(-1000.0)' }).stats.completed_goal_lists, 1, 'normal exp behavior');
328
+ equal(run('', { goal: 'X is 2.0 ** -1075.0' }).stats.completed_goal_lists, 1, 'normal power behavior');
329
+ });
330
+
331
+ reporter.test('preserves prescribed power errors before integer-to-float conversion', () => {
332
+ const hugeNegative = `-1${'0'.repeat(400)}`;
333
+ equal(capture(() => run('', { isoStrict: true, goal: 'X is (-2) ** 2.0' })).formal,
334
+ 'evaluation_error(undefined)', '**/2 negative base requires integer-typed exponent');
335
+ equal(run('', { isoStrict: true, goal: 'X is (-2.0) ** 2' }).stats.completed_goal_lists,
336
+ 1, '**/2 negative base with integer exponent');
337
+ equal(run('', { isoStrict: true, goal: 'X is (-2) ^ 2.0' }).stats.completed_goal_lists,
338
+ 1, 'Corrigendum 2 ^/2 accepts integer-valued float exponent');
339
+ equal(capture(() => run('', { isoStrict: true, goal: 'X is (-2) ^ 0.5' })).formal,
340
+ 'evaluation_error(undefined)', 'Corrigendum 2 ^/2 fractional exponent');
341
+ equal(capture(() => run('', { isoStrict: true, goal: `X is ${hugeNegative} ** 0.5` })).formal,
342
+ 'evaluation_error(undefined)', 'undefined power precedes base conversion overflow');
343
+ equal(capture(() => run('', { isoStrict: true, goal: `X is 0.0 ** (${hugeNegative})` })).formal,
344
+ 'evaluation_error(undefined)', 'zero-negative power precedes exponent conversion overflow');
345
+ });
346
+
303
347
  reporter.test('uses the Part 1 mixed arithmetic comparison operations', () => {
304
348
  // 8.7 converts the integer operand to float in mixed comparisons.
305
349
  equal(run('', { isoStrict: true, goal: '18014398509481985 =:= 18014398509481984.0' }).stats.completed_goal_lists,
@@ -362,8 +406,15 @@ export function runIsoStrict(reporter = new TestReporter()) {
362
406
  });
363
407
 
364
408
  reporter.test('pins applicable post-Corrigendum STC clarifications', () => {
409
+ equal(capture(() => run('', { isoStrict: true, goal: 'X is 1/0+_' })).formal,
410
+ 'instantiation_error', 'STC 17 direct variable precedes zero divisor on the other branch');
411
+ equal(capture(() => run('', { isoStrict: true, goal: 'X is _+1/0' })).formal,
412
+ 'instantiation_error', 'STC 17 is independent of operand order');
413
+
365
414
  equal(run('', { isoStrict: true, goal: 'integer(- /**/ 1)' }).stats.completed_goal_lists,
366
415
  1, 'layout between minus and integer token');
416
+ equal(run('', { isoStrict: true, goal: "number_chars(N,['0','1']),N=1" }).stats.completed_goal_lists,
417
+ 1, 'STC 32 number_chars/2 follows the procedural number syntax for leading zero');
367
418
 
368
419
  const shared = run(
369
420
  ':- dynamic(a/1).\na(X) :- b(X).\n',
@@ -387,7 +438,13 @@ export function runIsoStrict(reporter = new TestReporter()) {
387
438
 
388
439
  Program.parse(':- op(500,xfx,foo).\na foo b.\n', { isoStrict: true });
389
440
  const beforeDefinition = capture(() => Program.parse('a foo b.\n:- op(500,xfx,foo).\n', { isoStrict: true }));
390
- includes(beforeDefinition.message, 'expected .', 'op/3 directive applies only to following text');
441
+ includes(beforeDefinition.message, 'expected .', 'STC 41 op/3 directive applies only to following text');
442
+
443
+ equal(run('', {
444
+ isoStrict: true,
445
+ goal: 'read_term(T,[variables([])])',
446
+ ioOptions: { input: 'T.' },
447
+ }).stats.completed_goal_lists, 0, 'STC 48 variables([]) does not match an input variable');
391
448
  });
392
449
 
393
450
  reporter.test('rejects EyeProlog module directives', () => {