eyeprolog 1.1.27 → 1.1.28

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.1.27",
6
+ "version": "1.1.28",
7
7
  "description": "EyeProlog turns facts and rules into answers and proofs.",
8
8
  "type": "module",
9
9
  "main": "./index.js",
package/src/iso.js CHANGED
@@ -1783,7 +1783,7 @@ function* phraseBuiltin({ solver, goal, env }) {
1783
1783
  solver.absorbStatsFrom(child);
1784
1784
  }
1785
1785
  }
1786
- function formalErrorTerm(error) {
1786
+ export function formalErrorTerm(error) {
1787
1787
  const context = error.contextTerm ?? atom('eyeprolog');
1788
1788
  if (error.formalTerm != null) return compound('error', [error.formalTerm, context]);
1789
1789
  const parse = (text) => {
package/src/repl.js CHANGED
@@ -2,6 +2,7 @@
2
2
  import fs from 'node:fs/promises';
3
3
  import path from 'node:path';
4
4
  import { createInterface } from 'node:readline';
5
+ import { formalErrorTerm } from './iso.js';
5
6
 
6
7
  const ANSWER_HELP = `
7
8
  SPACE, "n" or ";": next solution, if any
@@ -425,46 +426,17 @@ function formatError(engine, state, error) {
425
426
  const env = new engine.Env();
426
427
  const variableNames = new Map();
427
428
  let generated = 0;
428
- if (error.formalTerm != null) {
429
- collectUnboundVariables(engine, error.formalTerm, env, variableNames, () => `_${letterName(generated++)}`);
430
- if (error.contextTerm != null) {
431
- collectUnboundVariables(engine, error.contextTerm, env, variableNames, () => `_${letterName(generated++)}`);
432
- }
433
- const formal = engine.formatTermForWrite(error.formalTerm, env, {
434
- quoted: true,
435
- operators: [...state.program.operators.values()],
436
- variableNames,
437
- });
438
- if (error.contextTerm != null) {
439
- const context = engine.formatTermForWrite(error.contextTerm, env, {
440
- quoted: true,
441
- operators: [...state.program.operators.values()],
442
- variableNames,
443
- });
444
- return `error(${formal}, ${context}).`;
445
- }
446
- return `error(${formal}).`;
447
- }
448
- if (error.culprit != null) {
449
- collectUnboundVariables(engine, error.culprit, env, variableNames, () => `_${letterName(generated++)}`);
450
- }
451
- if (error.contextTerm != null) {
452
- collectUnboundVariables(engine, error.contextTerm, env, variableNames, () => `_${letterName(generated++)}`);
453
- }
454
- const culprit = error.culprit == null ? '' : `, ${engine.formatTermForWrite(error.culprit, env, {
429
+ // ISO 7.12.1 represents processor errors as error(ErrorTerm, ImpDef).
430
+ // Reuse the same conversion as catch/3 so uncaught errors at the top
431
+ // level cannot lose the implementation-defined context or misplace a
432
+ // culprit as the second argument of error/2.
433
+ const term = formalErrorTerm(error);
434
+ collectUnboundVariables(engine, term, env, variableNames, () => `_${letterName(generated++)}`);
435
+ return `${engine.formatTermForWrite(term, env, {
455
436
  quoted: true,
456
437
  operators: [...state.program.operators.values()],
457
438
  variableNames,
458
- })}`;
459
- if (error.contextTerm != null) {
460
- const context = engine.formatTermForWrite(error.contextTerm, env, {
461
- quoted: true,
462
- operators: [...state.program.operators.values()],
463
- variableNames,
464
- });
465
- return `error(${error.formal}${culprit}, ${context}).`;
466
- }
467
- return `error(${error.formal}${culprit}).`;
439
+ })}.`;
468
440
  }
469
441
  const message = error?.message ?? String(error);
470
442
  return message.endsWith('.') ? message : `${message}.`;
@@ -533,8 +533,23 @@ c4 ?- call((!;1)).
533
533
  });
534
534
  assertEqual(result.status, 0, 'exit status');
535
535
  assertEqual(result.stdout,
536
- '?- error(type_error(list), [1, [], _A | 2]).\n' +
537
- '?- error(type_error(list), [1, [], _A | 2]).\n' +
536
+ '?- error(type_error(list, [1, [], _A | 2]), eyeprolog).\n' +
537
+ '?- error(type_error(list, [1, [], _A | 2]), eyeprolog).\n' +
538
+ '?- ',
539
+ 'stdout');
540
+ assertEqual(result.stderr, '', 'stderr');
541
+ },
542
+ },
543
+ {
544
+ name: 'REPL uncaught ISO errors retain the error/2 implementation context',
545
+ run: () => {
546
+ const result = runCli([], {
547
+ input: '_ is _.\ncatch(_ is _, error(Error, Imp_def), true).\nhalt.\n',
548
+ });
549
+ assertEqual(result.status, 0, 'exit status');
550
+ assertEqual(result.stdout,
551
+ '?- error(instantiation_error, eyeprolog).\n' +
552
+ '?- Error = instantiation_error, Imp_def = eyeprolog.\n' +
538
553
  '?- ',
539
554
  'stdout');
540
555
  assertEqual(result.stderr, '', 'stderr');
@@ -5803,11 +5803,14 @@ instances whose message contains the corresponding Prolog error term.
5803
5803
  `error(Formal,eyeprolog)` term. `throw/1` copies its ball before unwinding: bound
5804
5804
  parts are preserved, repeated variables remain shared within the copied ball,
5805
5805
  and unbound variables are fresh with respect to the protected goal and catcher.
5806
- Catchable error terms follow the same variable-freshening rule. At the interactive
5807
- top level, variables that occur in an uncaught ISO error are rendered with fresh
5808
- answer names such as `_A` rather than reusing query-variable spellings such as
5809
- `X` or `Xx`; this keeps the displayed error consistent with the copied exception
5810
- term. An unmatched ball or error continues outward.
5806
+ Catchable error terms follow the same variable-freshening rule. The interactive
5807
+ top level uses the same ISO error envelope for uncaught processor errors, so an
5808
+ ordinary runtime error is displayed as `error(Formal,eyeprolog)` rather than
5809
+ dropping the implementation-defined second argument. Variables that occur in an
5810
+ uncaught ISO error are rendered with fresh answer names such as `_A` rather than
5811
+ reusing query-variable spellings such as `X` or `Xx`; this keeps the displayed
5812
+ error consistent with the copied exception term. An unmatched ball or error
5813
+ continues outward.
5811
5814
 
5812
5815
  Streams belong to one solver run and are shared by nested calls, exceptions,
5813
5816
  and solution collectors. `user_input` and `user_output` are always present.