eyeprolog 1.3.2 → 1.3.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/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.3.2",
6
+ "version": "1.3.3",
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
@@ -6,7 +6,7 @@ import {
6
6
  properListItems, termIsGround, termToString, unify, variable, variantTerms,
7
7
  } from './term.js';
8
8
  import { sameNumberValue } from './number-value.js';
9
- import { createParserOperatorState, parseClauses, parseGoalText, parseNumberTokenText } from './parser.js';
9
+ import { createParserOperatorState, parseGoalText, parseNumberTokenText, parseTermText } from './parser.js';
10
10
  import { formatTermForWrite } from './write.js';
11
11
  import { emptyTerminalSequence, expandDcgBody, isListOrPartialList, validateDcgEmbeddedGoals } from './dcg.js';
12
12
  import {
@@ -1199,8 +1199,7 @@ function scopeReadTerm(term) {
1199
1199
  function parseReadTermText(text, solver) {
1200
1200
  const converted = convertedTermText(text, solver);
1201
1201
  const operatorState = createParserOperatorState(solver.program.operators.values(), false);
1202
- const clauses = parseClauses(converted, {
1203
- sourceMetadata: false,
1202
+ return parseTermText(converted, {
1204
1203
  operatorState,
1205
1204
  isoStrict: solver.isoStrict,
1206
1205
  doubleQuotes: solver.prologFlags.get('double_quotes')?.value?.name ?? 'chars',
@@ -1208,8 +1207,6 @@ function parseReadTermText(text, solver) {
1208
1207
  // Earlier ambiguous dots must remain available to maximal graphic tokens.
1209
1208
  readTermEnd: converted.length - 1,
1210
1209
  });
1211
- if (clauses.length !== 1 || clauses[0].body.length) throw new Error('bad term');
1212
- return clauses[0].head;
1213
1210
  }
1214
1211
 
1215
1212
  export function isCompleteReadTermText(text, solver) {
package/src/parser.js CHANGED
@@ -819,6 +819,16 @@ class Parser {
819
819
  }
820
820
  throw new Error(`parse line ${this.token.line}: bad term`);
821
821
  }
822
+ parseStandaloneTerm() {
823
+ // read/1 and read_term/* consume one ordinary Prolog term, not a program
824
+ // clause. In particular, commas and operators such as :- and ?- belong to
825
+ // the term itself and must not be reinterpreted by parseProgram().
826
+ const term = this.parseTerm(0, true, true, true);
827
+ this.expect(TOK.DOT, '.');
828
+ this.advance();
829
+ this.expect(TOK.EOF, 'end of input');
830
+ return term;
831
+ }
822
832
  sourceLineIsIndented(line) {
823
833
  let start = 0;
824
834
  for (let current = 1; current < line; current++) {
@@ -1504,6 +1514,10 @@ export function parseNumberTokenText(text) {
1504
1514
  return numberTerm(source);
1505
1515
  }
1506
1516
 
1517
+ export function parseTermText(text, options = {}) {
1518
+ return new Parser(text, options).parseStandaloneTerm();
1519
+ }
1520
+
1507
1521
  export function parseGoalText(text, options = {}) {
1508
1522
  const clauses = parseClauses(`zz_goal((${text})).`, options);
1509
1523
  const head = clauses[0]?.head;
@@ -819,6 +819,27 @@ c4 ?- call((!;1)).
819
819
  });
820
820
  assertEqual(consecutive.stdout, "answer(./*., ok).\n", 'following read starts after the complete term');
821
821
 
822
+ // Issue #41 follow-up: read/1 consumes an ordinary term, not a program
823
+ // clause head. A comma chain therefore has no program-level two-comma
824
+ // limit, and source operators such as :- and ?- remain term data.
825
+ const commaChain = runEyeProlog('', {
826
+ goal: 'read(T)',
827
+ ioOptions: { input: '!,!,! .\n' },
828
+ });
829
+ assertEqual(commaChain.stdout, 'read((!, !, !)).\n', 'three-element comma term');
830
+
831
+ const ruleAsData = runEyeProlog('', {
832
+ goal: 'read(T)',
833
+ ioOptions: { input: 'a :- b.\n' },
834
+ });
835
+ assertEqual(ruleAsData.stdout, 'read((a :- b)).\n', 'rule operator remains term data');
836
+
837
+ const queryAsData = runEyeProlog('', {
838
+ goal: 'read(T)',
839
+ ioOptions: { input: '?- foo.\n' },
840
+ });
841
+ assertEqual(queryAsData.stdout, 'read((?- foo)).\n', 'query operator remains term data');
842
+
822
843
  // A possible full stop can fail to complete the term while still
823
844
  // extending a current graphic operator into an ordinary atom. The
824
845
  // later standalone full stop then completes the read term. Exercise