eyeprolog 1.2.36 → 1.2.37

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.2.36",
6
+ "version": "1.2.37",
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
@@ -617,6 +617,7 @@ function formatAnswer(engine, state, variables, env) {
617
617
  // current operator atoms in argument and list-element positions without
618
618
  // quotes, just as writeq/1 already prints them.
619
619
  operatorAtomsAsArgs: true,
620
+ dottedGraphicAtoms: true,
620
621
  doubleQuotes: state.solver.prologFlags.get('double_quotes')?.value?.name ?? 'chars',
621
622
  })}`);
622
623
  }
package/src/write.js CHANGED
@@ -5,6 +5,7 @@ import {
5
5
  } from './term.js';
6
6
 
7
7
  const graphicAtomCharacters = new Set('!#$&*+-/<=>?@^~\\'.split(''));
8
+ const dottedGraphicAtomCharacters = new Set([...graphicAtomCharacters, '.']);
8
9
  const compactInfixOperators = new Set([':', '..']);
9
10
 
10
11
  function quotedControlEscape(ch) {
@@ -48,6 +49,11 @@ function writeAtom(name) {
48
49
  return atomNeedsQuotes(name) ? quoteAtom(name) : name;
49
50
  }
50
51
 
52
+ function isDottedGraphicAtom(name) {
53
+ return name.includes('.') && [...name].some((ch) => ch !== '.') && !name.startsWith('/*') &&
54
+ [...name].every((ch) => dottedGraphicAtomCharacters.has(ch));
55
+ }
56
+
51
57
  function legacyVariableToIso(name) {
52
58
  if (name === '?') return '_';
53
59
  const tail = name.slice(1);
@@ -172,6 +178,10 @@ function format(term, env, options, table, maxPriority = 1200, context = 'term')
172
178
  if (resolved.type === STRING) return writeString(resolved.name);
173
179
  if (resolved.type === ATOM) {
174
180
  if (!options.quoted) return resolved.name;
181
+ // Top-level bindings are already delimited by their answer punctuation.
182
+ // Keep valid dotted graphic tokens readable there without weakening the
183
+ // ISO writeq/1 policy tested by WG17 #308.
184
+ if (options.dottedGraphicAtoms && isDottedGraphicAtom(resolved.name)) return resolved.name;
175
185
  // ISO 6.3.3.1 gives functional arguments and list elements a special
176
186
  // `arg` production: an atom that is a current operator is valid there
177
187
  // without quoting. Keep lexical exceptions such as `|` quoted.
@@ -269,6 +279,7 @@ export function formatTermForWrite(term, env = new Env(), options = {}) {
269
279
  variableNames: printableReadVariableNames(term, env, explicitVariableNames),
270
280
  compact: options.compact === true,
271
281
  operatorAtomsAsArgs: options.operatorAtomsAsArgs === true,
282
+ dottedGraphicAtoms: options.dottedGraphicAtoms === true,
272
283
  };
273
284
  const maxPriority = Number.isInteger(options.maxPriority)
274
285
  ? Math.max(0, Math.min(1200, options.maxPriority))
@@ -764,7 +764,8 @@ c4 ?- call((!;1)).
764
764
  input: 'read(T).\n./*. .\nread(T).\nok.\nread(T).\n!.!.\nhalt.\n',
765
765
  });
766
766
  assertEqual(repl.status, 0, 'REPL exit status');
767
- assertIncludes(repl.stdout, "T = './*.'.", 'REPL dotted graphic atom answer');
767
+ assertIncludes(repl.stdout, 'T = ./*..', 'REPL dotted graphic atom answer');
768
+ assertNotIncludes(repl.stdout, "T = './*.'", 'REPL dotted graphic atom has no spurious quotes');
768
769
  assertIncludes(repl.stdout, 'T = ok.', 'REPL following read answer');
769
770
  assertIncludes(repl.stdout, 'error(syntax_error(read_term), eyeprolog)', 'REPL syntax error');
770
771
  assertEqual(repl.stderr, '', 'REPL stderr');