eyeprolog 1.5.1 → 1.5.3

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/README.md CHANGED
@@ -31,8 +31,6 @@ Run EyeProlog without installing it globally:
31
31
 
32
32
  ```sh
33
33
  npx --yes eyeprolog
34
- ?- use_module(library(lists)).
35
- true.
36
34
  ?- member(X, [prolog, logic]).
37
35
  X = prolog
38
36
  ; X = logic.
@@ -63,7 +61,9 @@ printf 'human(socrates).\nmortal(X) :- human(X).\n' |
63
61
  Normal mode executes top-level `Conclusion :+ Premise` rules natively when no explicit
64
62
  `-g/--goal` is supplied. `true :+ Goal` prints answers and `false :+ Goal` emits a
65
63
  `fuse/1`; JavaScript `run()` follows the same rule. Strict ISO mode disables this
66
- extension. See [*The Art of EyeProlog*](the-art-of-eyeprolog.md) for the full semantics.
64
+ extension. Bundled `src/lib/` predicates autoload in files, CLI/API goals, and the REPL;
65
+ use `--no-autoload` to require explicit imports, and explicitly import libraries that introduce
66
+ operators before using their syntax. See [*The Art of EyeProlog*](the-art-of-eyeprolog.md) for the full semantics.
67
67
 
68
68
  ## Links
69
69
 
package/index.d.ts CHANGED
@@ -289,6 +289,9 @@ export const eyePrologLibraryIndicators: readonly string[];
289
289
  export const eyePrologNativeLibraryIndicators: readonly string[];
290
290
  export const eyePrologPortableLibraryIndicators: readonly string[];
291
291
  export const eyePrologInteropAutoload: Readonly<Record<string, string>>;
292
+ export const eyePrologLibraryAutoload: Readonly<Record<string, string>>;
293
+ export const eyePrologAmbiguousLibraryAutoload: Readonly<Record<string, readonly string[]>>;
294
+ export const eyePrologLibraryAutoloadModules: readonly string[];
292
295
  export const eyePrologInteropLibraryIndicators: readonly string[];
293
296
  export const eyePrologInteropLibraryModules: readonly string[];
294
297
  export class PrologError extends Error {
@@ -374,6 +377,9 @@ declare const eyeprolog: {
374
377
  eyePrologNativeLibraryIndicators: typeof eyePrologNativeLibraryIndicators;
375
378
  eyePrologPortableLibraryIndicators: typeof eyePrologPortableLibraryIndicators;
376
379
  eyePrologInteropAutoload: typeof eyePrologInteropAutoload;
380
+ eyePrologLibraryAutoload: typeof eyePrologLibraryAutoload;
381
+ eyePrologAmbiguousLibraryAutoload: typeof eyePrologAmbiguousLibraryAutoload;
382
+ eyePrologLibraryAutoloadModules: typeof eyePrologLibraryAutoloadModules;
377
383
  eyePrologInteropLibraryIndicators: typeof eyePrologInteropLibraryIndicators;
378
384
  eyePrologInteropLibraryModules: typeof eyePrologInteropLibraryModules;
379
385
  run: typeof run;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.5.1",
6
+ "version": "1.5.3",
7
7
  "description": "EyeProlog turns facts and rules into answers and proofs.",
8
8
  "type": "module",
9
9
  "main": "./index.js",
@@ -46,7 +46,8 @@
46
46
  },
47
47
  "scripts": {
48
48
  "test": "node test/run-all.mjs",
49
- "generate": "node tools/extract-book-examples.mjs",
49
+ "generate": "node tools/generate-library-autoload-index.mjs && node tools/extract-book-examples.mjs",
50
+ "generate:autoload": "node tools/generate-library-autoload-index.mjs",
50
51
  "test:eyeprolog": "node test/run-all.mjs",
51
52
  "test:conformance": "node test/run-conformance.mjs",
52
53
  "test:iso-strict": "node test/run-iso-strict.mjs",
package/src/cli.js CHANGED
@@ -281,7 +281,7 @@ Options:
281
281
  --iso-strict Use ISO/IEC 13211-1 core + Corrigenda 1-3 only;
282
282
  reject EyeProlog language extensions.
283
283
  --portable Enforce the EyeProlog/Trealla/Scryer interop profile.
284
- --no-autoload Disable conservative interop predicate autoloading.
284
+ --no-autoload Disable bundled library predicate autoloading.
285
285
  -v, --version Show the package version and exit.
286
286
  -w, --warnings Print non-fatal portability warnings to stderr.
287
287
  -g, --goal goal Solve goal and print its ground answers; may be repeated.
package/src/index.js CHANGED
@@ -21,6 +21,9 @@ export {
21
21
  eyePrologNativeLibraryIndicators,
22
22
  eyePrologPortableLibraryIndicators,
23
23
  eyePrologInteropAutoload,
24
+ eyePrologLibraryAutoload,
25
+ eyePrologAmbiguousLibraryAutoload,
26
+ eyePrologLibraryAutoloadModules,
24
27
  eyePrologInteropLibraryIndicators,
25
28
  eyePrologInteropLibraryModules,
26
29
  } from './standard-library.js';
@@ -0,0 +1,346 @@
1
+ // Generated by tools/generate-library-autoload-index.mjs.
2
+ // Do not edit by hand; module/2 export lists under src/lib/ are the source of truth.
3
+
4
+ export const eyePrologLibraryAutoload = Object.freeze({
5
+ ",/3": "reif",
6
+ ";/3": "reif",
7
+ ".../2": "iso_ext",
8
+ "*/1": "debug",
9
+ "\\/1": "lambda",
10
+ "\\/2": "lambda",
11
+ "\\/3": "lambda",
12
+ "\\/4": "lambda",
13
+ "\\/5": "lambda",
14
+ "\\/6": "lambda",
15
+ "\\/7": "lambda",
16
+ "\\/8": "lambda",
17
+ "#/\\/2": "clpz",
18
+ "#\\//2": "clpz",
19
+ "#\\/1": "clpz",
20
+ "#\\/2": "clpz",
21
+ "#\\=/2": "clpz",
22
+ "#</2": "clpz",
23
+ "#</3": "clpz",
24
+ "#<==/2": "clpz",
25
+ "#<==>/2": "clpz",
26
+ "#=/2": "clpz",
27
+ "#=/3": "clpz",
28
+ "#=</2": "clpz",
29
+ "#==>/2": "clpz",
30
+ "#>/2": "clpz",
31
+ "#>=/2": "clpz",
32
+ "^/10": "lambda",
33
+ "^/3": "lambda",
34
+ "^/4": "lambda",
35
+ "^/5": "lambda",
36
+ "^/6": "lambda",
37
+ "^/7": "lambda",
38
+ "^/8": "lambda",
39
+ "^/9": "lambda",
40
+ "+\\/2": "lambda",
41
+ "+\\/3": "lambda",
42
+ "+\\/4": "lambda",
43
+ "+\\/5": "lambda",
44
+ "+\\/6": "lambda",
45
+ "+\\/7": "lambda",
46
+ "+\\/8": "lambda",
47
+ "+\\/9": "lambda",
48
+ "=/3": "reif",
49
+ "$-/1": "debug",
50
+ "$/1": "debug",
51
+ "abolish_all_tables/0": "tabling",
52
+ "add_edges/3": "ugraphs",
53
+ "add_vertices/3": "ugraphs",
54
+ "aggregate_max/5": "aggregate",
55
+ "aggregate_min/5": "aggregate",
56
+ "all_different/1": "clpz",
57
+ "all_distinct/1": "clpz",
58
+ "append/2": "lists",
59
+ "append/3": "lists",
60
+ "assoc_to_keys/2": "assoc",
61
+ "assoc_to_list/2": "assoc",
62
+ "assoc_to_values/2": "assoc",
63
+ "atom_si/1": "si",
64
+ "atom_string/2": "strings",
65
+ "atomic_si/1": "si",
66
+ "automaton/3": "clpz",
67
+ "automaton/8": "clpz",
68
+ "bb_b_put/2": "debug",
69
+ "bb_get/2": "debug",
70
+ "bb_global_get/2": "debug",
71
+ "bb_put/2": "debug",
72
+ "between/3": "between",
73
+ "call_nth/2": "iso_ext",
74
+ "call_residue_vars/2": "atts",
75
+ "call_with_error_context/2": "error",
76
+ "can_be/2": "error",
77
+ "cfor/3": "iso_ext",
78
+ "chain/2": "clpz",
79
+ "char_type/2": "charsio",
80
+ "character_si/1": "si",
81
+ "chars_si/1": "si",
82
+ "circuit/1": "clpz",
83
+ "clpz_t/2": "clpz",
84
+ "complement/2": "ugraphs",
85
+ "compose/3": "ugraphs",
86
+ "cond_t/3": "reif",
87
+ "connect_ugraph/3": "ugraphs",
88
+ "contains/2": "strings",
89
+ "copy_term_nat/2": "terms",
90
+ "countall/2": "iso_ext",
91
+ "cumulative/1": "clpz",
92
+ "cumulative/2": "clpz",
93
+ "current_time/1": "time",
94
+ "debug/1": "debug",
95
+ "debug/3": "debug",
96
+ "del_assoc/4": "assoc",
97
+ "del_attr/2": "atts",
98
+ "del_edges/3": "ugraphs",
99
+ "del_max_assoc/4": "assoc",
100
+ "del_min_assoc/4": "assoc",
101
+ "del_vertices/3": "ugraphs",
102
+ "dif_si/2": "si",
103
+ "dif/2": "dif",
104
+ "dif/3": "reif",
105
+ "difference/3": "dates",
106
+ "disjoint2/1": "clpz",
107
+ "domain_error/2": "error",
108
+ "domain_error/3": "error",
109
+ "drop/3": "lists",
110
+ "edges/2": "ugraphs",
111
+ "element/3": "clpz",
112
+ "empty_assoc/1": "assoc",
113
+ "fd_dom/2": "clpz",
114
+ "fd_inf/2": "clpz",
115
+ "fd_size/2": "clpz",
116
+ "fd_sup/2": "clpz",
117
+ "fd_var/1": "clpz",
118
+ "findall/4": "iso_ext",
119
+ "foldl/4": "lists",
120
+ "foldl/5": "lists",
121
+ "foldl/6": "lists",
122
+ "forall/2": "iso_ext",
123
+ "format_/4": "format",
124
+ "format_time/4": "time",
125
+ "format/2": "format",
126
+ "format/3": "format",
127
+ "freeze/2": "freeze",
128
+ "ge/2": "comparison",
129
+ "gen_assoc/3": "assoc",
130
+ "gen_int/1": "between",
131
+ "gen_nat/1": "between",
132
+ "gensym/2": "gensym",
133
+ "get_assoc/3": "assoc",
134
+ "get_assoc/5": "assoc",
135
+ "get_attr/3": "atts",
136
+ "get_atts/2": "atts",
137
+ "get_line_to_chars/3": "charsio",
138
+ "get_n_chars/3": "charsio",
139
+ "get_single_char/1": "charsio",
140
+ "global_cardinality/2": "clpz",
141
+ "global_cardinality/3": "clpz",
142
+ "group_pairs_by_key/2": "pairs",
143
+ "gt/2": "comparison",
144
+ "if_/3": "reif",
145
+ "in/2": "clpz",
146
+ "indomain/1": "clpz",
147
+ "ins/2": "clpz",
148
+ "instantiation_error/0": "error",
149
+ "instantiation_error/1": "error",
150
+ "integer_si/1": "si",
151
+ "is_assoc/1": "assoc",
152
+ "is_ordset/1": "ordsets",
153
+ "join/3": "strings",
154
+ "label/1": "clpz",
155
+ "labeling/1": "clpb",
156
+ "labeling/2": "clpz",
157
+ "last/2": "lists",
158
+ "le/2": "comparison",
159
+ "length/2": "lists",
160
+ "lex_chain/1": "clpz",
161
+ "list_max/2": "lists",
162
+ "list_min/2": "lists",
163
+ "list_si/1": "si",
164
+ "list_to_assoc/2": "assoc",
165
+ "list_to_ord_set/2": "ordsets",
166
+ "list_to_set/2": "lists",
167
+ "listing/1": "format",
168
+ "lowercase/2": "strings",
169
+ "lsb/2": "arithmetic",
170
+ "lt/2": "comparison",
171
+ "map_assoc/2": "assoc",
172
+ "map_assoc/3": "assoc",
173
+ "map_list_to_pairs/3": "pairs",
174
+ "maplist/2": "lists",
175
+ "maplist/3": "lists",
176
+ "maplist/4": "lists",
177
+ "maplist/5": "lists",
178
+ "maplist/6": "lists",
179
+ "maplist/7": "lists",
180
+ "maplist/8": "lists",
181
+ "matches/2": "strings",
182
+ "matches/3": "strings",
183
+ "max_assoc/3": "assoc",
184
+ "max_list/2": "lists",
185
+ "maybe/0": "random",
186
+ "member/2": "lists",
187
+ "memberchk/2": "lists",
188
+ "memberd_t/3": "reif",
189
+ "min_assoc/3": "assoc",
190
+ "min_list/2": "lists",
191
+ "msb/2": "arithmetic",
192
+ "must_be/2": "error",
193
+ "neighbors/3": "ugraphs",
194
+ "neighbours/3": "ugraphs",
195
+ "nodebug/1": "debug",
196
+ "not_si/1": "si",
197
+ "nth0/3": "lists",
198
+ "nth0/4": "lists",
199
+ "nth1/3": "lists",
200
+ "nth1/4": "lists",
201
+ "number_string/2": "strings",
202
+ "numbervars/3": "terms",
203
+ "numlist/2": "between",
204
+ "numlist/3": "between",
205
+ "nvalue/2": "clpz",
206
+ "ord_add_element/3": "ordsets",
207
+ "ord_del_element/3": "ordsets",
208
+ "ord_disjoint/2": "ordsets",
209
+ "ord_empty/1": "ordsets",
210
+ "ord_intersect/2": "ordsets",
211
+ "ord_intersect/3": "ordsets",
212
+ "ord_intersection/2": "ordsets",
213
+ "ord_intersection/3": "ordsets",
214
+ "ord_intersection/4": "ordsets",
215
+ "ord_list_to_assoc/2": "assoc",
216
+ "ord_memberchk/2": "ordsets",
217
+ "ord_selectchk/3": "ordsets",
218
+ "ord_seteq/2": "ordsets",
219
+ "ord_subset/2": "ordsets",
220
+ "ord_subtract/3": "ordsets",
221
+ "ord_symdiff/3": "ordsets",
222
+ "ord_union/2": "ordsets",
223
+ "ord_union/3": "ordsets",
224
+ "ord_union/4": "ordsets",
225
+ "pairs_keys_values/3": "pairs",
226
+ "pairs_keys/2": "pairs",
227
+ "pairs_values/2": "pairs",
228
+ "permutation/2": "lists",
229
+ "phrase_from_file/2": "pio",
230
+ "phrase_from_file/3": "pio",
231
+ "phrase_to_file/2": "pio",
232
+ "phrase_to_file/3": "pio",
233
+ "phrase_to_stream/2": "pio",
234
+ "phrase/2": "dcgs",
235
+ "phrase/3": "dcgs",
236
+ "popcount/2": "arithmetic",
237
+ "portray_clause_/3": "format",
238
+ "portray_clause/1": "format",
239
+ "portray_clause/2": "format",
240
+ "put_assoc/4": "assoc",
241
+ "put_attr/3": "atts",
242
+ "put_atts/2": "atts",
243
+ "random_integer/3": "random",
244
+ "random_labeling/2": "clpb",
245
+ "random/1": "random",
246
+ "random/3": "random",
247
+ "reachable/3": "ugraphs",
248
+ "repeat/1": "between",
249
+ "replace/4": "strings",
250
+ "representation_error/1": "error",
251
+ "reset_gensym/1": "gensym",
252
+ "resource_error/1": "error",
253
+ "reverse/2": "lists",
254
+ "same_length/2": "lists",
255
+ "sat_count/2": "clpb",
256
+ "sat/1": "clpb",
257
+ "scalar_product/4": "clpz",
258
+ "select/3": "lists",
259
+ "seq/3": "dcgs",
260
+ "seqq/3": "dcgs",
261
+ "serialized/2": "clpz",
262
+ "set_nth0/4": "lists",
263
+ "set_random/1": "random",
264
+ "slice/4": "lists",
265
+ "smallest_divisor_from/3": "primes",
266
+ "split/3": "strings",
267
+ "start_tabling/2": "tabling",
268
+ "string_concat/3": "strings",
269
+ "substring/4": "strings",
270
+ "succ/2": "iso_ext",
271
+ "sum_list/2": "lists",
272
+ "sum/3": "clpz",
273
+ "sumall/3": "aggregate",
274
+ "take/3": "lists",
275
+ "taut/2": "clpb",
276
+ "term_attributed_variables/2": "atts",
277
+ "term_si/1": "si",
278
+ "term_string/2": "strings",
279
+ "tfilter/3": "reif",
280
+ "time/1": "iso_ext",
281
+ "tmember_t/3": "reif",
282
+ "tmember/2": "reif",
283
+ "top_sort/2": "ugraphs",
284
+ "top_sort/3": "ugraphs",
285
+ "tpartition/4": "reif",
286
+ "transitive_closure/2": "ugraphs",
287
+ "transpose_ugraph/2": "ugraphs",
288
+ "transpose/2": "lists",
289
+ "trim/2": "strings",
290
+ "tuples_in/2": "clpz",
291
+ "type_error/2": "error",
292
+ "type_error/3": "error",
293
+ "ugraph_union/3": "ugraphs",
294
+ "uppercase/2": "strings",
295
+ "uuid_string/2": "uuid",
296
+ "uuid/3": "uuid",
297
+ "uuidv4_string/1": "uuid",
298
+ "uuidv4/1": "uuid",
299
+ "variant/2": "iso_ext",
300
+ "vertices_edges_to_ugraph/3": "ugraphs",
301
+ "vertices/2": "ugraphs",
302
+ "weighted_maximum/3": "clpb",
303
+ "when_si/2": "si",
304
+ "when/2": "when",
305
+ "zcompare/3": "clpz"
306
+ });
307
+
308
+ export const eyePrologAmbiguousLibraryAutoload = Object.freeze({});
309
+
310
+ export const eyePrologLibraryAutoloadModules = Object.freeze([
311
+ "aggregate",
312
+ "arithmetic",
313
+ "assoc",
314
+ "atts",
315
+ "between",
316
+ "charsio",
317
+ "clpb",
318
+ "clpz",
319
+ "comparison",
320
+ "dates",
321
+ "dcgs",
322
+ "debug",
323
+ "dif",
324
+ "error",
325
+ "format",
326
+ "freeze",
327
+ "gensym",
328
+ "iso_ext",
329
+ "lambda",
330
+ "lists",
331
+ "ordsets",
332
+ "pairs",
333
+ "pio",
334
+ "primes",
335
+ "prologue",
336
+ "random",
337
+ "reif",
338
+ "si",
339
+ "strings",
340
+ "tabling",
341
+ "terms",
342
+ "time",
343
+ "ugraphs",
344
+ "uuid",
345
+ "when"
346
+ ]);
package/src/program.js CHANGED
@@ -12,11 +12,12 @@ import {
12
12
  parseGoalText,
13
13
  tryParseClausesFastInto,
14
14
  } from './parser.js';
15
- import { PrologError, convertClauseBodyTerm, getStrictIsoRegistry } from './iso.js';
15
+ import { PrologError, convertClauseBodyTerm, getDefaultRegistry, getStrictIsoRegistry } from './iso.js';
16
16
  import { currentWorkingDirectory, fs, path } from './platform.js';
17
17
  import {
18
18
  standardLibrarySources,
19
- eyePrologInteropAutoload,
19
+ eyePrologAmbiguousLibraryAutoload,
20
+ eyePrologLibraryAutoload,
20
21
  eyePrologInteropLibraryIndicators,
21
22
  eyePrologInteropLibraryModules,
22
23
  } from './standard-library.js';
@@ -255,7 +256,10 @@ export class Program {
255
256
  }
256
257
  }
257
258
  this.initializations = [];
258
- this._initializationsExecuted = false;
259
+ // Track how many initialization/1 directives have run so a REPL can
260
+ // autoload a library after startup and execute only that library's newly
261
+ // appended initializations without repeating earlier side effects.
262
+ this._initializationsExecutedCount = 0;
259
263
  this.quads = [];
260
264
  this.prologFlagDirectives = [];
261
265
  this.charConversionDirectives = [];
@@ -1045,7 +1049,7 @@ export function autoloadProgramGoals(program, inputs, options = {}) {
1045
1049
  const builder = new ProgramBuilder({ ...options, isoStrict: false }, program);
1046
1050
  const loadedModules = new Set([...program.modules.keys()].filter((name) => name !== 'user'));
1047
1051
  const autoloadCount = program.autoloadedPredicates.length;
1048
- autoloadInteropDependencies(builder, {
1052
+ autoloadLibraryDependencies(builder, {
1049
1053
  ...options,
1050
1054
  isoStrict: false,
1051
1055
  operatorState,
@@ -1094,7 +1098,7 @@ function loadSourcesIntoBuilder(builder, sources, options, fast) {
1094
1098
  parserFlagState,
1095
1099
  }, builder.program);
1096
1100
  if (options.isoStrict !== true && options.autoload !== false) {
1097
- autoloadInteropDependencies(builder, {
1101
+ autoloadLibraryDependencies(builder, {
1098
1102
  ...options,
1099
1103
  operatorState,
1100
1104
  parserFlagState,
@@ -1164,14 +1168,32 @@ function extraGoalDependencies(goals) {
1164
1168
  return dependencies;
1165
1169
  }
1166
1170
 
1167
- function interopAutoloadRequests(program, extraGoals = []) {
1171
+ function procedureResolvedBeforeAutoload(program, dependency, targetModule) {
1172
+ if (program.findGroup(dependency.name, dependency.arity, targetModule)) return true;
1173
+ return program.moduleImports.get(targetModule)?.has(dependency.key) === true;
1174
+ }
1175
+
1176
+ function autoloadLibraryFor(dependency) {
1177
+ // ISO built-ins always take precedence over optional library autoloading.
1178
+ if (getDefaultRegistry().get(dependency.name, dependency.arity) != null) return null;
1179
+ const ambiguous = eyePrologAmbiguousLibraryAutoload[dependency.key];
1180
+ if (ambiguous != null) {
1181
+ throw new PrologError(
1182
+ 'permission_error(import, procedure)',
1183
+ compound('/', [atom(dependency.name), numberTerm(dependency.arity)]),
1184
+ );
1185
+ }
1186
+ return eyePrologLibraryAutoload[dependency.key] ?? null;
1187
+ }
1188
+
1189
+ function libraryAutoloadRequests(program, extraGoals = []) {
1168
1190
  const requests = new Map();
1169
1191
  for (const group of program.groups.values()) {
1170
1192
  if (bundledLibraryModule(program, group.module)) continue;
1171
1193
  for (const dependency of groupDependencies(group)) {
1172
1194
  const targetModule = dependency.module ?? group.module;
1173
- if (program.findGroup(dependency.name, dependency.arity, targetModule)) continue;
1174
- const library = eyePrologInteropAutoload[dependency.key];
1195
+ if (procedureResolvedBeforeAutoload(program, dependency, targetModule)) continue;
1196
+ const library = autoloadLibraryFor(dependency);
1175
1197
  if (library == null) continue;
1176
1198
  const requestKey = `${targetModule}\u0000${dependency.key}`;
1177
1199
  requests.set(requestKey, {
@@ -1186,8 +1208,8 @@ function interopAutoloadRequests(program, extraGoals = []) {
1186
1208
  for (const goal of program.initializations) {
1187
1209
  for (const dependency of collectGoalDependencies(goal, false, true)) {
1188
1210
  const targetModule = dependency.module ?? 'user';
1189
- if (program.findGroup(dependency.name, dependency.arity, targetModule)) continue;
1190
- const library = eyePrologInteropAutoload[dependency.key];
1211
+ if (procedureResolvedBeforeAutoload(program, dependency, targetModule)) continue;
1212
+ const library = autoloadLibraryFor(dependency);
1191
1213
  if (library == null) continue;
1192
1214
  const requestKey = `${targetModule}\u0000${dependency.key}`;
1193
1215
  requests.set(requestKey, {
@@ -1201,8 +1223,8 @@ function interopAutoloadRequests(program, extraGoals = []) {
1201
1223
  }
1202
1224
  for (const dependency of extraGoalDependencies(extraGoals)) {
1203
1225
  const targetModule = dependency.module ?? 'user';
1204
- if (program.findGroup(dependency.name, dependency.arity, targetModule)) continue;
1205
- const library = eyePrologInteropAutoload[dependency.key];
1226
+ if (procedureResolvedBeforeAutoload(program, dependency, targetModule)) continue;
1227
+ const library = autoloadLibraryFor(dependency);
1206
1228
  if (library == null) continue;
1207
1229
  const requestKey = `${targetModule}\u0000${dependency.key}`;
1208
1230
  requests.set(requestKey, {
@@ -1216,14 +1238,14 @@ function interopAutoloadRequests(program, extraGoals = []) {
1216
1238
  return [...requests.values()];
1217
1239
  }
1218
1240
 
1219
- function autoloadInteropDependencies(builder, options, ensured, loadedModules, extraGoals = []) {
1241
+ function autoloadLibraryDependencies(builder, options, ensured, loadedModules, extraGoals = []) {
1220
1242
  const program = builder.program;
1221
1243
  while (true) {
1222
- const requests = interopAutoloadRequests(program, extraGoals);
1244
+ const requests = libraryAutoloadRequests(program, extraGoals);
1223
1245
  if (requests.length === 0) return;
1224
1246
  let changed = false;
1225
1247
  for (const request of requests) {
1226
- if (program.findGroup(request.name, request.arity, request.targetModule)) continue;
1248
+ if (procedureResolvedBeforeAutoload(program, request, request.targetModule)) continue;
1227
1249
  if (!loadedModules.has(request.library)) {
1228
1250
  const designation = compound('library', [atom(request.library)]);
1229
1251
  const loaded = readModuleSource(designation, options);
package/src/repl.js CHANGED
@@ -4,6 +4,7 @@ import { readSync } from 'node:fs';
4
4
  import path from 'node:path';
5
5
  import { createInterface } from 'node:readline';
6
6
  import { formalErrorTerm } from './iso.js';
7
+ import { autoloadProgramGoals } from './program.js';
7
8
  import {
8
9
  characterCodeConstantEnd, continuesGraphicToken, isTerminatingFullStop, quotedEscapeEnd,
9
10
  } from './syntax-scan.js';
@@ -67,6 +68,19 @@ export async function runRepl(engine, options = {}) {
67
68
  continue;
68
69
  }
69
70
 
71
+ // Queries entered after the initial Program was prepared need the same
72
+ // bundled-library autoload resolution as file and -g execution. This
73
+ // is intentionally after parsing: predicate autoloading cannot provide
74
+ // syntax operators retroactively (libraries such as clpz must still be
75
+ // imported explicitly before their operators are used).
76
+ if (!state.strictIso && options.autoload !== false) {
77
+ autoloadProgramGoals(state.program, [goal], {
78
+ autoload: true,
79
+ doubleQuotes: state.solver.prologFlags.get('double_quotes')?.value?.name ?? 'chars',
80
+ });
81
+ runWithTerminalSignals(reader, () => state.solver.runInitializations());
82
+ }
83
+
70
84
  const flagsBefore = snapshotFlagValues(state.solver);
71
85
  try {
72
86
  await prepareInteractiveTermInput(state, goal, reader);
@@ -284,7 +298,11 @@ function runWithTerminalSignals(reader, operation) {
284
298
 
285
299
  function makeState(engine, sources, output, options = {}, previousState = null, reader = null) {
286
300
  const strictIso = options.isoStrict === true;
287
- const program = engine.Program.parseSources(sources, { strictIso, sourceMetadata: strictIso });
301
+ const program = engine.Program.parseSources(sources, {
302
+ isoStrict: strictIso,
303
+ sourceMetadata: strictIso,
304
+ autoload: !strictIso && options.autoload !== false,
305
+ });
288
306
  const solver = new engine.Solver(program, {
289
307
  registry: strictIso ? engine.getStrictIsoRegistry() : engine.getEyePrologRegistry(),
290
308
  isoStrict: strictIso,
@@ -756,12 +774,29 @@ function formatAnswer(engine, state, variables, env) {
756
774
  collectUnboundVariables(engine, residual, env, names, () => `_${letterName(generated++)}`);
757
775
  bindings.push(engine.formatTermForWrite(residual, env, answerWriteOptions));
758
776
  }
777
+ // Residual attributes are part of the answer even when the attributed
778
+ // variable was created inside a called predicate and is not itself a query
779
+ // variable (issue #87). First retain visible query names for attributed
780
+ // roots, then project every remaining live attributed root with a generated
781
+ // top-level variable name. This also makes call_residue_vars/2 useful at the
782
+ // top level: variables returned through its list share the same name with the
783
+ // projected constraint instead of appearing unconstrained.
759
784
  const projectedAttributeRoots = new Set();
785
+ const attributeRoots = [];
760
786
  for (const variable of variables) {
761
787
  const root = engine.deref(variable, env);
762
- if (root.type !== 'var' || projectedAttributeRoots.has(root.name) || !env.hasPrologAttributes?.(root.name)) continue;
763
- projectedAttributeRoots.add(root.name);
788
+ if (root.type !== 'var' || !env.hasPrologAttributes?.(root.name)) continue;
764
789
  names.set(root.name, variable.name);
790
+ attributeRoots.push(root);
791
+ }
792
+ for (const name of env.attributedVariableNames?.() ?? []) {
793
+ const root = engine.deref(engine.variable(name), env);
794
+ if (root.type === 'var') attributeRoots.push(root);
795
+ }
796
+ for (const root of attributeRoots) {
797
+ if (projectedAttributeRoots.has(root.name) || !env.hasPrologAttributes?.(root.name)) continue;
798
+ projectedAttributeRoots.add(root.name);
799
+ if (!names.has(root.name)) names.set(root.name, `_${letterName(generated++)}`);
765
800
  for (const residual of state.solver.attributeResidualGoals(root, env)) {
766
801
  collectUnboundVariables(engine, residual, env, names, () => `_${letterName(generated++)}`);
767
802
  bindings.push(engine.formatTermForWrite(residual, env, answerWriteOptions));
package/src/solver.js CHANGED
@@ -375,18 +375,19 @@ export class Solver {
375
375
  }
376
376
 
377
377
  runInitializations() {
378
- if (this.program._initializationsExecuted) return;
379
- for (const goal of this.program.initializations ?? []) {
378
+ const goals = this.program.initializations ?? [];
379
+ let index = this.program._initializationsExecutedCount ?? 0;
380
+ for (; index < goals.length; index++) {
380
381
  let succeeded = false;
381
- for (const _ of this.solve([goal], new Env(), 0)) {
382
+ for (const _ of this.solve([goals[index]], new Env(), 0)) {
382
383
  succeeded = true;
383
384
  break;
384
385
  }
385
386
  if (!succeeded) throw new PrologError('initialization_error');
387
+ // Mark each successful initialization immediately. If a later one fails,
388
+ // retrying does not repeat already completed initialization side effects.
389
+ this.program._initializationsExecutedCount = index + 1;
386
390
  }
387
- // 7.4.2.6 attaches initialization to preparation of the Prolog text, not
388
- // to each later Solver instance created for the same prepared Program.
389
- this.program._initializationsExecuted = true;
390
391
  }
391
392
 
392
393
  *solve(goals, env = new Env(), depth = 0) {