eyeprolog 1.1.24 → 1.1.25

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.24",
6
+ "version": "1.1.25",
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
@@ -1164,9 +1164,9 @@ function* readTermBuiltin({ solver, goal, env }) {
1164
1164
  yield next;
1165
1165
  }
1166
1166
  function defaultTermWriteOptions(mode) {
1167
- if (mode === 'writeq') return { quoted: true, ignoreOps: false, numbervars: true, variableNames: new Map() };
1168
- if (mode === 'canonical') return { quoted: true, ignoreOps: true, numbervars: false, variableNames: new Map() };
1169
- return { quoted: false, ignoreOps: false, numbervars: true, variableNames: new Map() };
1167
+ if (mode === 'writeq') return { quoted: true, ignoreOps: false, numbervars: true, variableNames: new Map(), compact: true, operatorAtomsAsArgs: true };
1168
+ if (mode === 'canonical') return { quoted: true, ignoreOps: true, numbervars: false, variableNames: new Map(), compact: true, operatorAtomsAsArgs: true };
1169
+ return { quoted: false, ignoreOps: false, numbervars: true, variableNames: new Map(), compact: true, operatorAtomsAsArgs: true };
1170
1170
  }
1171
1171
 
1172
1172
  function writeOptionBoolean(value, env, option) {
package/src/write.js CHANGED
@@ -124,11 +124,18 @@ function chooseOperator(term, table) {
124
124
  return null;
125
125
  }
126
126
 
127
- function format(term, env, options, table, maxPriority = 1200) {
127
+ function format(term, env, options, table, maxPriority = 1200, context = 'term') {
128
128
  const resolved = deref(term, env);
129
129
  if (resolved.type === VAR) return options.variableNames.get(resolved.name) ?? writeVariable(resolved.name);
130
130
  if (resolved.type === STRING) return writeString(resolved.name);
131
- if (resolved.type === ATOM) return options.quoted ? writeAtom(resolved.name) : resolved.name;
131
+ if (resolved.type === ATOM) {
132
+ if (!options.quoted) return resolved.name;
133
+ // ISO 6.3.3.1 gives functional arguments and list elements a special
134
+ // `arg` production: an atom that is a current operator is valid there
135
+ // without quoting. Keep lexical exceptions such as `|` quoted.
136
+ if (options.operatorAtomsAsArgs && context === 'argument' && table.has(resolved.name)) return operatorName(resolved.name);
137
+ return writeAtom(resolved.name);
138
+ }
132
139
  if (resolved.type === NUMBER) return resolved.name;
133
140
 
134
141
  if (options.numbervars && resolved.type === COMPOUND && resolved.name === '$VAR' && resolved.arity === 1) {
@@ -146,9 +153,13 @@ function format(term, env, options, table, maxPriority = 1200) {
146
153
  let cursor = resolved;
147
154
  while (true) {
148
155
  cursor = deref(cursor, env);
149
- if (isEmptyList(cursor)) return `[${parts.join(', ')}]`;
150
- if (!isCons(cursor)) return `[${parts.join(', ')} | ${format(cursor, env, options, table, 999)}]`;
151
- parts.push(format(cursor.args[0], env, options, table, 999));
156
+ const separator = options.compact ? ',' : ', ';
157
+ if (isEmptyList(cursor)) return `[${parts.join(separator)}]`;
158
+ if (!isCons(cursor)) {
159
+ const tailSeparator = options.compact ? '|' : ' | ';
160
+ return `[${parts.join(separator)}${tailSeparator}${format(cursor, env, options, table, 999, 'argument')}]`;
161
+ }
162
+ parts.push(format(cursor.args[0], env, options, table, 999, 'argument'));
152
163
  cursor = cursor.args[1];
153
164
  }
154
165
  }
@@ -183,8 +194,8 @@ function format(term, env, options, table, maxPriority = 1200) {
183
194
  }
184
195
 
185
196
  const name = options.quoted ? writeAtom(resolved.name) : resolved.name;
186
- const args = resolved.args.map((arg) => format(arg, env, options, table, 999));
187
- return `${name}(${args.join(', ')})`;
197
+ const args = resolved.args.map((arg) => format(arg, env, options, table, 999, 'argument'));
198
+ return `${name}(${args.join(options.compact ? ',' : ', ')})`;
188
199
  }
189
200
 
190
201
  export function formatTermForWrite(term, env = new Env(), options = {}) {
@@ -194,6 +205,8 @@ export function formatTermForWrite(term, env = new Env(), options = {}) {
194
205
  numbervars: options.numbervars !== false,
195
206
  doubleQuotes: options.doubleQuotes,
196
207
  variableNames: options.variableNames instanceof Map ? options.variableNames : new Map(),
208
+ compact: options.compact === true,
209
+ operatorAtomsAsArgs: options.operatorAtomsAsArgs === true,
197
210
  };
198
211
  return format(term, env, normalized, operatorTable(options.operators), 1200);
199
212
  }
@@ -1,2 +1,2 @@
1
- pair(First, Second)
1
+ pair(First,Second)
2
2
  corrigendum3_write_variable_names.
@@ -950,6 +950,23 @@ c4 ?- call((!;1)).
950
950
  assertEqual(run(source, { goal: 'operator_argument(ok)' }).stdout, 'operator_argument(ok).\n', 'operator argument syntax');
951
951
  },
952
952
  },
953
+ {
954
+ name: 'ISO writeq preserves operator atoms in argument syntax',
955
+ run: () => {
956
+ const source = [
957
+ 'emit_operator_arguments :-',
958
+ " writeq([:-,-]), put_char('|'),",
959
+ " writeq(f(*)), put_char('|'),",
960
+ " writeq(f(;,'|',';;')).",
961
+ '',
962
+ ].join('\n');
963
+ assertEqual(
964
+ run(source, { goal: 'emit_operator_arguments' }).stdout,
965
+ "[:-,-]|f(*)|f(;,'|',';;')emit_operator_arguments.\n",
966
+ 'operator argument output',
967
+ );
968
+ },
969
+ },
953
970
  {
954
971
  name: 'ISO query operator and quad infix extension are visible through current_op/3',
955
972
  run: () => {
@@ -1020,7 +1037,7 @@ c4 ?- call((!;1)).
1020
1037
  ].join('\n');
1021
1038
  assertEqual(
1022
1039
  run(source, { goal: 'emit' }).stdout,
1023
- "hello world|'hello world'|a + b * c|'+'(a, *(b, c))|hello world|'hello world'|+(a, b)|a + b|A|$VAR(0)|pair(Left, Right)emit.\n",
1040
+ "hello world|'hello world'|a + b * c|'+'(a,*(b,c))|hello world|'hello world'|+(a,b)|a + b|A|$VAR(0)|pair(Left,Right)emit.\n",
1024
1041
  'stdout',
1025
1042
  );
1026
1043
  },
@@ -5131,7 +5131,12 @@ parsing of subsequent text, place them before their first use. ISO argument
5131
5131
  syntax also permits an atom that is currently an operator to appear directly
5132
5132
  as a functional argument or list element, so forms such as
5133
5133
  `current_op(Priority, Specifier, :-)` and `[:-,-]` are valid without quoting
5134
- or parenthesizing those operator atoms. The ISO initial operator table also
5134
+ or parenthesizing those operator atoms. Term output observes the same `arg`
5135
+ rule: with `quoted(true)`, an operator atom is not quoted merely because it is
5136
+ an operator when it occurs as a functional argument or list element. Thus
5137
+ `writeq([:-,-])` emits `[:-,-]`, and `writeq(f(;,'|',';;'))` emits
5138
+ `f(;,'|',';;')`; the bar stays quoted because ISO treats the unquoted `|`
5139
+ token as a list separator rather than an atom. The ISO initial operator table also
5135
5140
  contains `?-` at priority 1200 with specifier `fx`, so
5136
5141
  `current_op(1200, fx, ?-)` succeeds. EyeProlog's embedded quad syntax permits
5137
5142
  an optional label before the query marker (`Label ?- Query.`), so while quad
@@ -5171,7 +5176,10 @@ write_event(Path, Event) :-
5171
5176
 
5172
5177
  The period is essential when another Prolog processor will read the result as
5173
5178
  a term. `write/1-2` uses readable conventional syntax, `writeq/1-2` quotes
5174
- where needed, and `write_canonical/1-2` exposes canonical structure.
5179
+ where needed, and `write_canonical/1-2` exposes canonical structure. ISO term
5180
+ output uses only the separator characters needed by the syntax, so functional
5181
+ arguments and list elements are emitted compactly; for example `writeq([a,b])`
5182
+ outputs `[a,b]`.
5175
5183
  `write_term/2-3` supports `quoted/1`, `ignore_ops/1`, `numbervars/1`, and
5176
5184
  `variable_names/1`.
5177
5185