eyeprolog 1.5.18 → 1.5.19

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.5.18",
6
+ "version": "1.5.19",
7
7
  "description": "EyeProlog turns facts and rules into answers and proofs.",
8
8
  "type": "module",
9
9
  "main": "./index.js",
@@ -188,6 +188,11 @@ function writeOptions(term, env, solver) {
188
188
  else if (option.name === 'double_quotes' && !solver.isoStrict) result.doubleQuotes = optionBoolean(option.args[0], env, option);
189
189
  else throw new PrologError('domain_error(write_option)', copyResolved(option, env));
190
190
  }
191
+ if (result.doubleQuotes === true) {
192
+ result.doubleQuotes = solver.prologFlags.get('double_quotes')?.value?.name ?? 'chars';
193
+ } else {
194
+ result.doubleQuotes = null;
195
+ }
191
196
  return result;
192
197
  }
193
198
 
package/src/write.js CHANGED
@@ -334,7 +334,11 @@ function format(term, env, options, table, maxPriority = 1200, context = 'term')
334
334
  }
335
335
  }
336
336
 
337
- if (!options.ignoreOps && isCons(resolved)) {
337
+ if (isCons(resolved)) {
338
+ // double_quotes/1 selects a character-list representation independently
339
+ // of operator notation. In normal mode, `||` is fixed list-splice syntax
340
+ // rather than an op/3 declaration, so ignore_ops(true) does not suppress
341
+ // an explicitly requested double-quoted proper or partial character list.
338
342
  const quotedSplice = quotedListSplice(resolved, env, options.doubleQuotes);
339
343
  if (quotedSplice != null && (quotedSplice.tail == null || options.doubleBar)) {
340
344
  const prefix = writeString(quotedSplice.text);
@@ -344,18 +348,21 @@ function format(term, env, options, table, maxPriority = 1200, context = 'term')
344
348
  // emitted text readable as the same term.
345
349
  return `${prefix}||${format(quotedSplice.tail, env, options, table, 1, 'term')}`;
346
350
  }
347
- const parts = [];
348
- let cursor = resolved;
349
- while (true) {
350
- cursor = deref(cursor, env);
351
- const separator = options.compact ? ',' : ', ';
352
- if (isEmptyList(cursor)) return `[${parts.join(separator)}]`;
353
- if (!isCons(cursor)) {
354
- const tailSeparator = options.compact ? '|' : ' | ';
355
- return `[${parts.join(separator)}${tailSeparator}${format(cursor, env, options, table, 999, 'argument')}]`;
351
+
352
+ if (!options.ignoreOps) {
353
+ const parts = [];
354
+ let cursor = resolved;
355
+ while (true) {
356
+ cursor = deref(cursor, env);
357
+ const separator = options.compact ? ',' : ', ';
358
+ if (isEmptyList(cursor)) return `[${parts.join(separator)}]`;
359
+ if (!isCons(cursor)) {
360
+ const tailSeparator = options.compact ? '|' : ' | ';
361
+ return `[${parts.join(separator)}${tailSeparator}${format(cursor, env, options, table, 999, 'argument')}]`;
362
+ }
363
+ parts.push(format(cursor.args[0], env, options, table, 999, 'argument'));
364
+ cursor = cursor.args[1];
356
365
  }
357
- parts.push(format(cursor.args[0], env, options, table, 999, 'argument'));
358
- cursor = cursor.args[1];
359
366
  }
360
367
  }
361
368
 
@@ -124,7 +124,7 @@ families; `--iso-strict` is intended to remove their Part 1 interpretation.
124
124
  | 5.5.9 Built-in predicates | EyeProlog libraries, CLP(Z), statistics, Part 3 `phrase/2-3`, and bundled-library autoloaded predicates | Strict registry contains only the Part 1 + Corrigenda core registry. |
125
125
  | 5.5.10 Evaluable functors | Normal mode additionally accepts the EyeProlog evaluable atom `e`; the remaining arithmetic functors accepted by strict mode are the Part 1 + Corrigenda set. | Strict mode rejects `e/0` as non-evaluable and retains the Corrigendum arithmetic additions. **covered** — strict extension-boundary regression plus `src/iso-arithmetic.js`. |
126
126
  | 5.5.11 Reserved atoms | None | None. |
127
- | Cor.3 5.5.12 Options | Extra library/host options may exist outside core option lists | Normal mode additionally accepts the EyeProlog `write_term/2-3` options `double_quotes(true|false)` and `spacing(true|false)`. `spacing(false)` emits only lexically required separators; `spacing(true)` adds conventional layout around operators. Strict core excludes these implementation-specific extensions and accepts only the Part 1 plus Corrigendum 3 write-option surface; unknown extension options raise `domain_error(write_option,...)`. |
127
+ | Cor.3 5.5.12 Options | Extra library/host options may exist outside core option lists | Normal mode additionally accepts the EyeProlog `write_term/2-3` options `double_quotes(true|false)` and `spacing(true|false)`. `double_quotes(true)` is orthogonal to `ignore_ops(true)`: eligible character/code lists retain double-quoted notation while operator terms use functional notation, and the order of those distinct options does not affect the result. `spacing(false)` emits only lexically required separators; `spacing(true)` adds conventional layout around operators. Strict core excludes these implementation-specific extensions and accepts only the Part 1 plus Corrigendum 3 write-option surface; unknown extension options raise `domain_error(write_option,...)`. |
128
128
 
129
129
  Normal mode provides documented module and DCG compatibility profiles whose
130
130
  features overlap standardized Part 2 and Part 3 facilities. They are extensions
@@ -7097,6 +7097,51 @@ function whiteBoxCases() {
7097
7097
  }
7098
7098
  },
7099
7099
  },
7100
+ {
7101
+ name: 'double_quotes(true) remains effective with ignore_ops(true) in either option order (issue #88 follow-up)',
7102
+ run: () => {
7103
+ const source = [
7104
+ 'emit :-',
7105
+ ` write_term(f("ab",a+b), [double_quotes(true),ignore_ops(true),quoted(true)]), put_char('|'),`,
7106
+ ` write_term(f("ab",a+b), [ignore_ops(true),double_quotes(true),quoted(true)]), put_char('|'),`,
7107
+ ` write_term("ab"||tail, [double_quotes(true),ignore_ops(true)]), put_char('|'),`,
7108
+ ` write_term("ab"||tail, [ignore_ops(true),double_quotes(true)]), put_char('|'),`,
7109
+ ' write_term("ab", [double_quotes(false),ignore_ops(true)]).',
7110
+ '',
7111
+ ].join('\n');
7112
+ assertEqual(
7113
+ run(source, { goal: 'emit' }).stdout,
7114
+ 'f("ab",+(a,b))|f("ab",+(a,b))|"ab"||tail|"ab"||tail|.(a,.(b,[]))emit.\n',
7115
+ 'write_term option composition',
7116
+ );
7117
+
7118
+ const codesSource = [
7119
+ 'emit_codes :-',
7120
+ ' set_prolog_flag(double_quotes, codes),',
7121
+ ' write_term([97,955], [ignore_ops(true),double_quotes(true)]).',
7122
+ '',
7123
+ ].join('\n');
7124
+ assertEqual(run(codesSource, { goal: 'emit_codes' }).stdout, '"aλ"emit_codes.\n',
7125
+ 'double_quotes(codes) representation');
7126
+ },
7127
+ },
7128
+ {
7129
+ name: 'charsio write_term_to_chars composes double_quotes with ignore_ops',
7130
+ run: () => {
7131
+ const source = [
7132
+ ':- use_module(library(charsio)).',
7133
+ 'answer(A,B) :-',
7134
+ ' write_term_to_chars(f("ab",a+b), [double_quotes(true),ignore_ops(true)], A),',
7135
+ ' write_term_to_chars("ab"||tail, [ignore_ops(true),double_quotes(true)], B).',
7136
+ '',
7137
+ ].join('\n');
7138
+ assertEqual(
7139
+ run(source, { goal: 'answer(A,B)' }).stdout,
7140
+ 'answer("f(\\"ab\\",+(a,b))", "\\"ab\\"||tail").\n',
7141
+ 'charsio output',
7142
+ );
7143
+ },
7144
+ },
7100
7145
  {
7101
7146
  name: 'REPL prints partial character lists with double-bar syntax (issue #88)',
7102
7147
  run: () => {
@@ -5482,8 +5482,12 @@ still retained where adjacent graphic tokens would otherwise merge, as in
5482
5482
  `double_quotes(true|false)`: `true` lets eligible character/code lists use the
5483
5483
  current `double_quotes` representation. Proper lists can therefore be written
5484
5484
  as `"text"`, while a partial list such as `[a,b|Tail]` is written as
5485
- `"ab"||Tail`. Strict ISO mode rejects this implementation-specific write
5486
- option. Normal mode also accepts the
5485
+ `"ab"||Tail`. This representation choice is independent of `ignore_ops/1`: with
5486
+ `ignore_ops(true)`, operator terms use functional notation while an explicitly
5487
+ requested character/code list remains double quoted. Thus
5488
+ `write_term(f("ab",a+b),[quoted(true),ignore_ops(true),double_quotes(true)])`
5489
+ emits `f("ab",+(a,b))`. Reversing the two options has the same effect. Strict
5490
+ ISO mode rejects this implementation-specific write option. Normal mode also accepts the
5487
5491
  implementation-specific boolean `spacing(true|false)` option: `false` emits
5488
5492
  only separators required to avoid lexical ambiguity, while `true` adds
5489
5493
  conventional layout around operators. For example,
@@ -6175,7 +6179,7 @@ the beginning. A peek does not mark the stream as past-end.
6175
6179
  - **`write(+Term)`, `write(+Stream,+Term)`** — Writes readable operator notation without quoting atoms merely because quoting would be required for reparsing. Number variables are enabled.
6176
6180
  - **`writeq(+Term)`, `writeq(+Stream,+Term)`** — Like `write`, but quotes atoms when required for unambiguous input syntax.
6177
6181
  - **`write_canonical(+Term)`, `write_canonical(+Stream,+Term)`** — Writes quoted canonical functor notation while ignoring operators and without interpreting *$VAR/1*.
6178
- - **`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)* and *spacing(true or false)*.
6182
+ - **`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)* and *spacing(true or false)*. `double_quotes(true)` remains effective with `ignore_ops(true)`: operator terms are written functionally while eligible character/code lists retain double-quoted notation, independently of option order.
6179
6183
 
6180
6184
  Term input uses the program's current operator table and the same ISO quoted-character
6181
6185
  syntax as source text, including backslash-terminated octal and hexadecimal