eyeprolog 1.1.22 → 1.1.23

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.22",
6
+ "version": "1.1.23",
7
7
  "description": "EyeProlog turns facts and rules into answers and proofs.",
8
8
  "type": "module",
9
9
  "main": "./index.js",
package/src/parser.js CHANGED
@@ -39,6 +39,7 @@ const graphicAtomChars = '#$&*+-./<=>@^~\\:';
39
39
  // canonical notation. Commas remain separators except inside parentheses.
40
40
  const INFIX_OPERATORS = new Map([
41
41
  [':-', { precedence: 1, associativity: 'none' }],
42
+ ['?-', { precedence: 1, associativity: 'none' }], // quad label extension
42
43
  ['-->', { precedence: 1, associativity: 'none' }],
43
44
  ['|', { precedence: 96, associativity: 'right' }],
44
45
  [';', { precedence: 101, associativity: 'right' }],
@@ -77,14 +78,15 @@ const INFIX_OPERATORS = new Map([
77
78
  ['^', { precedence: 1001, associativity: 'right' }],
78
79
  ]);
79
80
  const PREFIX_OPERATORS = new Map([
80
- ['\\+', 301],
81
- ['+', 1001],
82
- ['-', 1001],
83
- ['\\', 1001],
81
+ ['?-', { precedence: 1, strict: true }],
82
+ ['\\+', { precedence: 301, strict: false }],
83
+ ['+', { precedence: 1001, strict: false }],
84
+ ['-', { precedence: 1001, strict: false }],
85
+ ['\\', { precedence: 1001, strict: false }],
84
86
  ]);
85
87
 
86
88
  export const ISO_OPERATOR_DEFINITIONS = [
87
- [1200, 'xfx', ':-'], [1200, 'fx', ':-'], [1200, 'xfx', '-->'],
89
+ [1200, 'xfx', ':-'], [1200, 'fx', ':-'], [1200, 'fx', '?-'], [1200, 'xfx', '-->'],
88
90
  [1105, 'xfy', '|'],
89
91
  [1100, 'xfy', ';'], [1050, 'xfy', '->'], [1000, 'xfy', ','],
90
92
  [900, 'fy', '\\+'],
@@ -97,6 +99,13 @@ export const ISO_OPERATOR_DEFINITIONS = [
97
99
  [200, 'fy', '+'], [200, 'fy', '-'], [200, 'fy', '\\'],
98
100
  ];
99
101
 
102
+ // EyeProlog's embedded quad syntax permits an optional label before `?-`.
103
+ // That makes `?-` an implementation-specific xfx operator in addition to its
104
+ // ISO 1200 fx definition.
105
+ export const QUAD_OPERATOR_DEFINITIONS = [
106
+ [1200, 'xfx', '?-'],
107
+ ];
108
+
100
109
  const CLPZ_OPERATOR_DEFINITIONS = [
101
110
  [760, 'yfx', '#<==>'], [750, 'xfy', '#==>'], [750, 'yfx', '#<=='],
102
111
  [740, 'yfx', '#\\/'], [730, 'yfx', '#\\'], [720, 'yfx', '#/\\'],
@@ -133,9 +142,7 @@ function defineParserOperator(state, priority, specifier, name) {
133
142
  export function createParserOperatorState(definitions = [], includeDefaults = true) {
134
143
  const state = {
135
144
  infixOperators: includeDefaults ? new Map(INFIX_OPERATORS) : new Map(),
136
- prefixOperators: includeDefaults
137
- ? new Map([...PREFIX_OPERATORS].map(([name, precedence]) => [name, { precedence, strict: false }]))
138
- : new Map(),
145
+ prefixOperators: includeDefaults ? new Map(PREFIX_OPERATORS) : new Map(),
139
146
  postfixOperators: new Map(),
140
147
  };
141
148
  for (const definition of definitions) {
package/src/program.js CHANGED
@@ -4,6 +4,7 @@ import { ATOM, COMPOUND, VAR, Env, atom, compound, deref, flattenConjunction, is
4
4
  import { formatTermForWrite } from './write.js';
5
5
  import {
6
6
  ISO_OPERATOR_DEFINITIONS,
7
+ QUAD_OPERATOR_DEFINITIONS,
7
8
  createParserOperatorState,
8
9
  parseClauses,
9
10
  parseClausesInto,
@@ -101,8 +102,10 @@ export class Program {
101
102
  this.moduleMetaPredicates = new Map();
102
103
  this.dynamicPredicates = new Set();
103
104
  this.operators = new Map();
104
- for (const [priority, specifier, name] of ISO_OPERATOR_DEFINITIONS) {
105
- this.defineOperator(priority, specifier, name);
105
+ for (const definitions of [ISO_OPERATOR_DEFINITIONS, QUAD_OPERATOR_DEFINITIONS]) {
106
+ for (const [priority, specifier, name] of definitions) {
107
+ this.defineOperator(priority, specifier, name);
108
+ }
106
109
  }
107
110
  this.initializations = [];
108
111
  this.quads = [];
@@ -5,3 +5,10 @@
5
5
  operator_atoms(Priority, Specifier, List) :-
6
6
  current_op(Priority, Specifier, :-),
7
7
  List = [:-,-].
8
+
9
+ % ISO 6.3.4.4, Table 7: ?- is a predefined 1200 fx operator.
10
+
11
+ %% goal: query_prefix_operator(ok)
12
+
13
+ query_prefix_operator(ok) :-
14
+ current_op(1200, fx, ?-).
@@ -1,2 +1,3 @@
1
1
  operator_atoms(1200, xfx, [':-', '-']).
2
2
  operator_atoms(1200, fx, [':-', '-']).
3
+ query_prefix_operator(ok).
@@ -950,6 +950,32 @@ 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 query operator and quad infix extension are visible through current_op/3',
955
+ run: () => {
956
+ assertEqual(
957
+ run('', { goal: 'current_op(Priority, Specifier, ?-)' }).stdout,
958
+ "current_op(1200, fx, '?-').\ncurrent_op(1200, xfx, '?-').\n",
959
+ 'query operator definitions',
960
+ );
961
+ assertEqual(
962
+ run('', { goal: 'current_op(1200, fx, ?-)' }).stdout,
963
+ "current_op(1200, fx, '?-').\n",
964
+ 'ISO query prefix operator',
965
+ );
966
+ assertEqual(
967
+ run('', { goal: 'current_op(1200, xfx, ?-)' }).stdout,
968
+ "current_op(1200, xfx, '?-').\n",
969
+ 'quad query infix operator',
970
+ );
971
+ const prefix = parseGoalText('(?- true)');
972
+ assertEqual(prefix.name, '?-', 'prefix query functor');
973
+ assertEqual(prefix.arity, 1, 'prefix query arity');
974
+ const infix = parseGoalText('(label ?- true)');
975
+ assertEqual(infix.name, '?-', 'quad query functor');
976
+ assertEqual(infix.arity, 2, 'quad query arity');
977
+ },
978
+ },
953
979
  {
954
980
  name: 'term input keeps dotted operators intact and uses program operators',
955
981
  run: () => {
@@ -5124,7 +5124,13 @@ parsing of subsequent text, place them before their first use. ISO argument
5124
5124
  syntax also permits an atom that is currently an operator to appear directly
5125
5125
  as a functional argument or list element, so forms such as
5126
5126
  `current_op(Priority, Specifier, :-)` and `[:-,-]` are valid without quoting
5127
- or parenthesizing those operator atoms.
5127
+ or parenthesizing those operator atoms. The ISO initial operator table also
5128
+ contains `?-` at priority 1200 with specifier `fx`, so
5129
+ `current_op(1200, fx, ?-)` succeeds. EyeProlog's embedded quad syntax permits
5130
+ an optional label before the query marker (`Label ?- Query.`), so while quad
5131
+ syntax is supported it additionally exposes `?-` at priority 1200 with
5132
+ specifier `xfx` as an implementation-specific operator. Consequently
5133
+ `current_op(Priority, Specifier, ?-)` enumerates both definitions.
5128
5134
 
5129
5135
  Run [`iso-dynamic-database.pl`](https://github.com/eyereasoner/eyeprolog/blob/main/examples/iso-dynamic-database.pl)
5130
5136
  for an explicitly stateful queue and
@@ -5290,8 +5296,10 @@ clause ends in a period. The grammar above gives the canonical term shapes.
5290
5296
  The initial operator table contains the following ISO-style operators, all
5291
5297
  lowered to ordinary compound terms:
5292
5298
 
5293
- - prefix: `\+`, unary `+`, unary `-`, and `\`;
5299
+ - prefix: ISO `?-`, `\+`, unary `+`, unary `-`, and `\`;
5294
5300
  - control: `,`, `;`, and `->`;
5301
+ - quad syntax extension: `?-` is also a priority-1200 `xfx` operator so a
5302
+ label may precede a quad query;
5295
5303
  - grammar rules: `-->` and the Part 3 alternative `|`;
5296
5304
  - unification and comparison: `=`, `\=`, `==`, `\==`, `@<`, `@=<`, `@>`,
5297
5305
  `@>=`, `is`, `=:=`, `=\=`, `<`, `=<`, `>`, and `>=`;