eyeprolog 1.3.82 → 1.3.84

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.82",
6
+ "version": "1.3.84",
7
7
  "description": "EyeProlog turns facts and rules into answers and proofs.",
8
8
  "type": "module",
9
9
  "main": "./index.js",
package/src/repl.js CHANGED
@@ -720,6 +720,15 @@ function formatAnswer(engine, state, variables, env) {
720
720
  const valueMaxPriority = equality == null
721
721
  ? 699
722
722
  : equality.specifier === 'xfy' ? equality.priority : equality.priority - 1;
723
+ const answerWriteOptions = {
724
+ quoted: true,
725
+ minimalOperatorSpacing: true,
726
+ operators,
727
+ variableNames: names,
728
+ operatorAtomsAsArgs: true,
729
+ dottedGraphicAtoms: true,
730
+ doubleQuotes: state.solver.prologFlags.get('double_quotes')?.value?.name ?? 'chars',
731
+ };
723
732
  let generated = 0;
724
733
 
725
734
  // Meta-predicate wrappers can make a query variable alias an internal fresh
@@ -734,30 +743,18 @@ function formatAnswer(engine, state, variables, env) {
734
743
  if (value.type === 'var' &&
735
744
  (value.name === variable.name || !queryVariableNames.has(value.name))) continue;
736
745
  bindings.push(`${variable.name} = ${engine.formatTermForWrite(value, env, {
737
- quoted: true,
738
- operators,
739
- variableNames: names,
746
+ ...answerWriteOptions,
740
747
  maxPriority: valueMaxPriority,
741
748
  // A binding value is the right-hand `arg` of =/2. ISO 6.3.3.1 permits
742
749
  // current operator atoms in argument and list-element positions without
743
750
  // quotes, just as writeq/1 already prints them.
744
- operatorAtomsAsArgs: true,
745
- dottedGraphicAtoms: true,
746
- doubleQuotes: state.solver.prologFlags.get('double_quotes')?.value?.name ?? 'chars',
747
751
  })}`);
748
752
  }
749
753
  for (const constraint of env.variableConstraints?.() ?? []) {
750
754
  const residual = constraint.residualGoal?.(env);
751
755
  if (residual == null) continue;
752
756
  collectUnboundVariables(engine, residual, env, names, () => `_${letterName(generated++)}`);
753
- bindings.push(engine.formatTermForWrite(residual, env, {
754
- quoted: true,
755
- operators,
756
- variableNames: names,
757
- operatorAtomsAsArgs: true,
758
- dottedGraphicAtoms: true,
759
- doubleQuotes: state.solver.prologFlags.get('double_quotes')?.value?.name ?? 'chars',
760
- }));
757
+ bindings.push(engine.formatTermForWrite(residual, env, answerWriteOptions));
761
758
  }
762
759
  const projectedAttributeRoots = new Set();
763
760
  for (const variable of variables) {
@@ -767,14 +764,7 @@ function formatAnswer(engine, state, variables, env) {
767
764
  names.set(root.name, variable.name);
768
765
  for (const residual of state.solver.attributeResidualGoals(root, env)) {
769
766
  collectUnboundVariables(engine, residual, env, names, () => `_${letterName(generated++)}`);
770
- bindings.push(engine.formatTermForWrite(residual, env, {
771
- quoted: true,
772
- operators,
773
- variableNames: names,
774
- operatorAtomsAsArgs: true,
775
- dottedGraphicAtoms: true,
776
- doubleQuotes: state.solver.prologFlags.get('double_quotes')?.value?.name ?? 'chars',
777
- }));
767
+ bindings.push(engine.formatTermForWrite(residual, env, answerWriteOptions));
778
768
  }
779
769
  }
780
770
  return bindings.length === 0 ? 'true' : bindings.join(', ');
@@ -186,7 +186,7 @@ function regressionCases() {
186
186
  });
187
187
  assertEqual(residuals.status, 0, 'dif/2 residual display status');
188
188
  assertEqual(residuals.stdout,
189
- '?- C = z, D = z, dif(A - z, B - z).\n' +
189
+ '?- C = z, D = z, dif(A-z, B-z).\n' +
190
190
  '?- A = [[]], B = [], dif([[]], [C]).\n' +
191
191
  '?- X = Y.\n' +
192
192
  '?- ',
@@ -1449,7 +1449,7 @@ c4 ?- call((!;1)).
1449
1449
  input: 'read(T).\n!,*.\n.\nread(T).\na\n.\nhalt.\n',
1450
1450
  });
1451
1451
  assertEqual(continuedGraphic.status, 0, 'continued graphic operator REPL status');
1452
- assertIncludes(continuedGraphic.stdout, 'T = (!, *.).', 'continued graphic operator answer');
1452
+ assertIncludes(continuedGraphic.stdout, 'T = (!,*.).', 'continued graphic operator answer');
1453
1453
  assertIncludes(continuedGraphic.stdout, 'T = a.', 'read after continued graphic operator');
1454
1454
  assertNotIncludes(continuedGraphic.stdout, 'syntax_error', 'continued graphic operator syntax');
1455
1455
  assertEqual(continuedGraphic.stderr, '', 'continued graphic operator REPL stderr');
@@ -2456,10 +2456,10 @@ c4 ?- call((!;1)).
2456
2456
  });
2457
2457
  assertEqual(result.status, 0, 'exit status');
2458
2458
  assertEqual(result.stdout,
2459
- '?- T = (a = b).\n' +
2460
- '?- U = (a, b).\n' +
2461
- '?- V = (a ; b).\n' +
2462
- '?- W = a + b.\n' +
2459
+ '?- T = (a=b).\n' +
2460
+ '?- U = (a,b).\n' +
2461
+ '?- V = (a;b).\n' +
2462
+ '?- W = a+b.\n' +
2463
2463
  '?- ',
2464
2464
  'stdout');
2465
2465
  assertEqual(result.stderr, '', 'stderr');
@@ -2665,9 +2665,9 @@ c4 ?- call((!;1)).
2665
2665
  });
2666
2666
  assertEqual(result.status, 0, 'exit status');
2667
2667
  assertEqual(result.stdout,
2668
- '?- |: X = (_A = a).\n' +
2669
- '?- |: X = (_A = a).\n' +
2670
- "?- |: X = (_A = pair(_A, _B)), Vs = [_A, _B], Names = ['X' = _A, 'Y' = _B], Singletons = ['Y' = _B].\n" +
2668
+ '?- |: X = (_A=a).\n' +
2669
+ '?- |: X = (_A=a).\n' +
2670
+ "?- |: X = (_A=pair(_A, _B)), Vs = [_A, _B], Names = ['X'=_A, 'Y'=_B], Singletons = ['Y'=_B].\n" +
2671
2671
  '?- ',
2672
2672
  'stdout');
2673
2673
  assertEqual(result.stderr, '', 'stderr');
@@ -3881,6 +3881,21 @@ child.stdin.write(\`consult(${consultedAtom}).\\n\`);
3881
3881
  assertEqual(run(source, { goal: 'emit' }).stdout, '1+2|a+ -b|a+b*c\nemit.\n', 'minimal operator spacing');
3882
3882
  },
3883
3883
  },
3884
+ {
3885
+ name: 'REPL answers use only lexically required operator spacing (issue #76)',
3886
+ run: () => {
3887
+ const result = runCli([], {
3888
+ input: 'X=1*1.\nX=a + -b.\nhalt.\n',
3889
+ });
3890
+ assertEqual(result.status, 0, 'exit status');
3891
+ assertEqual(result.stdout,
3892
+ '?- X = 1*1.\n' +
3893
+ '?- X = a+ -b.\n' +
3894
+ '?- ',
3895
+ 'minimal operator layout preserves required token separation');
3896
+ assertEqual(result.stderr, '', 'stderr');
3897
+ },
3898
+ },
3884
3899
  {
3885
3900
  name: 'write predicates and write_term options select distinct formats',
3886
3901
  run: () => {
@@ -5427,7 +5427,9 @@ still retained where adjacent graphic tokens would otherwise merge, as in
5427
5427
  `variable_names/1`. Normal mode additionally accepts the EyeProlog extension
5428
5428
  `double_quotes(true|false)`: `true` lets eligible character/code lists use the
5429
5429
  current `double_quotes` representation, while strict ISO mode rejects this
5430
- non-standard write option.
5430
+ non-standard write option. The REPL follows the same minimal-separator rule as
5431
+ term output, so `X=1*1` is displayed as `X = 1*1`, while a separator is retained
5432
+ in `X = a+ -b` because the adjacent graphic tokens would otherwise merge.
5431
5433
 
5432
5434
  Character operations are `get_char`, `peek_char`, `put_char`, `get_code`,
5433
5435
  `peek_code`, and `put_code`; byte streams use the corresponding byte
@@ -6120,7 +6122,7 @@ the beginning. A peek does not mark the stream as past-end.
6120
6122
  | `write(+Term)`, `write(+Stream,+Term)` | Writes readable operator notation without quoting atoms merely because quoting would be required for reparsing. Number variables are enabled. |
6121
6123
  | `writeq(+Term)`, `writeq(+Stream,+Term)` | Like `write`, but quotes atoms when required for unambiguous input syntax. |
6122
6124
  | `write_canonical(+Term)`, `write_canonical(+Stream,+Term)` | Writes quoted canonical functor notation while ignoring operators and without interpreting *$VAR/1*. |
6123
- | `write_term(+Term,+Options)`, `write_term(+Stream,+Term,+Options)` | Writes with *quoted(true or false)*, *ignore_ops(true or false)*, *numbervars(true or false)*, and *variable_names([Name=Variable,...])*. |
6125
+ | `write_term(+Term,+Options)`, `write_term(+Stream,+Term,+Options)` | Writes with *quoted(true or false)*, *ignore_ops(true or false)*, *numbervars(true or false)*, and *variable_names([Name=Variable,...])*. Normal mode also supports *double_quotes(true or false)*. |
6124
6126
 
6125
6127
  Term input uses the program's current operator table and the same ISO quoted-character
6126
6128
  syntax as source text, including backslash-terminated octal and hexadecimal