eyeprolog 1.3.10 → 1.3.11

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.10",
6
+ "version": "1.3.11",
7
7
  "description": "EyeProlog turns facts and rules into answers and proofs.",
8
8
  "type": "module",
9
9
  "main": "./index.js",
package/src/term.js CHANGED
@@ -683,7 +683,13 @@ export function numberTextFromDouble(value) {
683
683
  if (Object.is(value, -0)) value = 0;
684
684
  let text = Number(value).toPrecision(17);
685
685
  if (text.includes('e') || text.includes('E')) {
686
- text = text.replace(/(\.\d*?[1-9])0+(e[+-]?\d+)$/i, '$1$2').replace(/\.0+(e[+-]?\d+)$/i, '$1');
686
+ text = text
687
+ .replace(/(\.\d*?[1-9])0+(e[+-]?\d+)$/i, '$1$2')
688
+ // ISO floating-point syntax requires a fractional part before the
689
+ // exponent. Keep one zero when the fraction is otherwise all zeros so
690
+ // generated text remains readable by EyeProlog itself (for example
691
+ // 1.0e-8 rather than JavaScript's 1e-8).
692
+ .replace(/\.0+(e[+-]?\d+)$/i, '.0$1');
687
693
  } else if (text.includes('.')) {
688
694
  text = text.replace(/0+$/, '').replace(/\.$/, '');
689
695
  }
@@ -31,6 +31,7 @@ import {
31
31
  compound,
32
32
  listFromItems,
33
33
  numberTerm,
34
+ numberTextFromDouble,
34
35
  stringTerm,
35
36
  variable,
36
37
  copyResolved,
@@ -697,6 +698,35 @@ c4 ?- call((!;1)).
697
698
  }
698
699
  },
699
700
  },
701
+ {
702
+ name: 'number_chars and number_codes keep exponent floats syntactically readable (issue #50)',
703
+ run: () => {
704
+ const source = `
705
+ ?- number_chars(1.0e-8,Cs).
706
+ Cs = "1.0e-8".
707
+ ?- number_chars(N,"1.0e-8"), number_chars(N,Cs).
708
+ N = 1.0e-8, Cs = "1.0e-8".
709
+ ?- number_codes(N,[49,46,48,101,45,56]), number_codes(N,Codes).
710
+ N = 1.0e-8, Codes = [49,46,48,101,45,56].
711
+ `;
712
+ const result = publicApi.runQuads(source);
713
+ assertEqual(result.total, 3, 'quad total');
714
+ assertEqual(result.passed, 3, 'quad passed');
715
+ assertEqual(result.failed, 0, 'quad failed');
716
+
717
+ const generated = numberTerm(numberTextFromDouble(1e-8));
718
+ assertEqual(generated.name, '1.0e-8', 'generated float spelling');
719
+ assertEqual(parseNumberTokenText(generated.name).name, '1.0e-8', 'generated spelling parses as a float');
720
+
721
+ for (const value of [1e-8, -1e-8, 1e20, 1e21, Number.MIN_VALUE, Number.MAX_VALUE]) {
722
+ const text = numberTextFromDouble(value);
723
+ if (/[eE]/.test(text)) {
724
+ assertEqual(/^-?\d+\.\d+[eE][+-]?\d+$/.test(text), true, `exponent float syntax ${text}`);
725
+ }
726
+ assertEqual(Number(parseNumberTokenText(text).name), value, `generated float round-trip ${text}`);
727
+ }
728
+ },
729
+ },
700
730
  {
701
731
  name: 'number syntax and number_chars normalize floating-point negative zero',
702
732
  run: () => {