eyeling 1.5.29 → 1.5.31

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
@@ -98,10 +98,10 @@ npm run test:package
98
98
  npm run test:packlist
99
99
  ```
100
100
 
101
- * `test:api` runs an independent JS API test suite (does not rely on `examples/`).
102
- * `test:examples` runs the examples in the `examples` directory and compares against the golden outputs in `examples/output`.
103
- * `test:package` does a “real consumer” smoke test: `npm pack` → install tarball into a temp project → run API + CLI + examples.
104
- * `test:packlist` sanity-checks what will be published in the npm tarball (and the CLI shebang/bin wiring).
101
+ - `test:api` runs an independent JS API test suite (does not rely on `examples/`).
102
+ - `test:examples` runs the examples in the `examples` directory and compares against the golden outputs in `examples/output`.
103
+ - `test:package` does a “real consumer” smoke test: `npm pack` → install tarball into a temp project → run API + CLI + examples.
104
+ - `test:packlist` sanity-checks what will be published in the npm tarball (and the CLI shebang/bin wiring).
105
105
 
106
106
  ### Run a single file
107
107
 
@@ -146,14 +146,14 @@ The proof comments are compact “local justifications” per derived triple (no
146
146
 
147
147
  ### Forward + backward chaining
148
148
 
149
- * **Forward chaining to fixpoint** for forward rules written as `{ P } => { C } .`
150
- * **Backward chaining (SLD-style)** for backward rules written as `{ H } <= { B } .` and for built-ins.
149
+ - **Forward chaining to fixpoint** for forward rules written as `{ P } => { C } .`
150
+ - **Backward chaining (SLD-style)** for backward rules written as `{ H } <= { B } .` and for built-ins.
151
151
 
152
152
  Forward rule premises are proved using:
153
153
 
154
- * ground facts (input + derived)
155
- * backward rules
156
- * built-ins
154
+ - ground facts (input + derived)
155
+ - backward rules
156
+ - built-ins
157
157
 
158
158
  The CLI prints only newly derived forward facts.
159
159
 
@@ -172,30 +172,28 @@ The CLI prints only newly derived forward facts.
172
172
 
173
173
  Supported:
174
174
 
175
- * `@prefix` / `@base`
176
- * triples with `;` and `,`
177
- * variables `?x`
178
- * blank nodes:
179
-
180
- * anonymous `[]`
181
- * property lists `[ :p :o; :q :r ]`
182
- * collections `( ... )`
183
- * quoted formulas `{ ... }`
184
- * implications:
185
-
186
- * forward rules `{ P } => { C } .`
187
- * backward rules `{ H } <= { B } .`
188
- * datatyped literals with `^^`
189
- * language-tagged string literals: `"hello"@en`, `"colour"@en-GB`
190
- * long string literals: `"""..."""` (can contain newlines; can also carry a language tag)
191
- * inverted predicate sugar: `?x <- :p ?y` (swaps subject/object for that predicate)
192
- * resource paths (forward `!` and reverse `^`): `:joe!:hasAddress!:hasCity "Metropolis".`
193
- * `#` line comments
175
+ - `@prefix` / `@base`
176
+ - triples with `;` and `,`
177
+ - variables `?x`
178
+ - blank nodes:
179
+ - anonymous `[]`
180
+ - property lists `[ :p :o; :q :r ]`
181
+ - collections `( ... )`
182
+ - quoted formulas `{ ... }`
183
+ - implications:
184
+ - forward rules `{ P } => { C } .`
185
+ - backward rules `{ H } <= { B } .`
186
+ - datatyped literals with `^^`
187
+ - language-tagged string literals: `"hello"@en`, `"colour"@en-GB`
188
+ - long string literals: `"""..."""` (can contain newlines; can also carry a language tag)
189
+ - inverted predicate sugar: `?x <- :p ?y` (swaps subject/object for that predicate)
190
+ - resource paths (forward `!` and reverse `^`): `:joe!:hasAddress!:hasCity "Metropolis".`
191
+ - `#` line comments
194
192
 
195
193
  Non-goals / current limits:
196
194
 
197
- * not a full W3C N3 grammar (some edge cases for identifiers, quantifiers, advanced syntax)
198
- * proof output is local per derived triple (not a global exported proof tree)
195
+ - not a full W3C N3 grammar (some edge cases for identifiers, quantifiers, advanced syntax)
196
+ - proof output is local per derived triple (not a global exported proof tree)
199
197
 
200
198
  ## Blank nodes and quantification (pragmatic N3/EYE-style)
201
199
 
@@ -213,12 +211,12 @@ Equal facts up to renaming of Skolem IDs are treated as duplicates and are not r
213
211
 
214
212
  Top level:
215
213
 
216
- * `{ P } log:implies { C } .` becomes a forward rule `{ P } => { C } .`
217
- * `{ H } log:impliedBy { B } .` becomes a backward rule `{ H } <= { B } .`
214
+ - `{ P } log:implies { C } .` becomes a forward rule `{ P } => { C } .`
215
+ - `{ H } log:impliedBy { B } .` becomes a backward rule `{ H } <= { B } .`
218
216
 
219
217
  During reasoning:
220
218
 
221
- * any **derived** `log:implies` / `log:impliedBy` triple with formula subject/object is turned into a new live forward/backward rule.
219
+ - any **derived** `log:implies` / `log:impliedBy` triple with formula subject/object is turned into a new live forward/backward rule.
222
220
 
223
221
  ## Inference fuse — `{ ... } => false.`
224
222
 
@@ -237,12 +235,12 @@ As soon as the premise is provable, `eyeling` exits with status code `2`.
237
235
 
238
236
  `eyeling` implements a pragmatic subset of common N3 builtin families and evaluates them during backward goal proving:
239
237
 
240
- * **crypto**: `crypto:md5` `crypto:sha` `crypto:sha256` `crypto:sha512`
241
- * **list**: `list:append` `list:first` `list:firstRest` `list:in` `list:iterate` `list:last` `list:length` `list:map` `list:member` `list:memberAt` `list:notMember` `list:remove` `list:rest` `list:reverse` `list:sort`
242
- * **log**: `log:collectAllIn` `log:equalTo` `log:forAllIn` `log:impliedBy` `log:implies` `log:notEqualTo` `log:notIncludes` `log:skolem` `log:uri`
243
- * **math**: `math:absoluteValue` `math:acos` `math:asin` `math:atan` `math:cos` `math:cosh` `math:degrees` `math:difference` `math:equalTo` `math:exponentiation` `math:greaterThan` `math:integerQuotient` `math:lessThan` `math:negation` `math:notEqualTo` `math:notGreaterThan` `math:notLessThan` `math:product` `math:quotient` `math:remainder` `math:rounded` `math:sin` `math:sinh` `math:sum` `math:tan` `math:tanh`
244
- * **string**: `string:concatenation` `string:contains` `string:containsIgnoringCase` `string:endsWith` `string:equalIgnoringCase` `string:format` `string:greaterThan` `string:lessThan` `string:matches` `string:notEqualIgnoringCase` `string:notGreaterThan` `string:notLessThan` `string:notMatches` `string:replace` `string:scrape` `string:startsWith`
245
- * **time**: `time:localTime`
238
+ - **crypto**: `crypto:md5` `crypto:sha` `crypto:sha256` `crypto:sha512`
239
+ - **list**: `list:append` `list:first` `list:firstRest` `list:in` `list:iterate` `list:last` `list:length` `list:map` `list:member` `list:memberAt` `list:notMember` `list:remove` `list:rest` `list:reverse` `list:sort`
240
+ - **log**: `log:collectAllIn` `log:equalTo` `log:forAllIn` `log:impliedBy` `log:implies` `log:notEqualTo` `log:notIncludes` `log:skolem` `log:uri`
241
+ - **math**: `math:absoluteValue` `math:acos` `math:asin` `math:atan` `math:cos` `math:cosh` `math:degrees` `math:difference` `math:equalTo` `math:exponentiation` `math:greaterThan` `math:integerQuotient` `math:lessThan` `math:negation` `math:notEqualTo` `math:notGreaterThan` `math:notLessThan` `math:product` `math:quotient` `math:remainder` `math:rounded` `math:sin` `math:sinh` `math:sum` `math:tan` `math:tanh`
242
+ - **string**: `string:concatenation` `string:contains` `string:containsIgnoringCase` `string:endsWith` `string:equalIgnoringCase` `string:format` `string:greaterThan` `string:lessThan` `string:matches` `string:notEqualIgnoringCase` `string:notGreaterThan` `string:notLessThan` `string:notMatches` `string:replace` `string:scrape` `string:startsWith`
243
+ - **time**: `time:localTime`
246
244
 
247
245
  ## License
248
246
 
@@ -242,6 +242,17 @@
242
242
  :status :pass .
243
243
  } .
244
244
 
245
+ # math:integerQuotient
246
+ { (10 3) math:integerQuotient ?q . ?q math:equalTo 3 . }
247
+ => {
248
+ :test-integerQuotient-1 a :MathBuiltinTest;
249
+ :builtin math:integerQuotient;
250
+ :input (10 3);
251
+ :expected 3;
252
+ :actual ?q;
253
+ :status :pass .
254
+ } .
255
+
245
256
  # math:lessThan
246
257
  {
247
258
  41 math:lessThan 42 .
@@ -1989,6 +1989,156 @@
1989
1989
 
1990
1990
  :test-greaterThan-1 :status :pass .
1991
1991
 
1992
+ # ----------------------------------------------------------------------
1993
+ # Proof for derived triple:
1994
+ # :test-integerQuotient-1 a :MathBuiltinTest .
1995
+ # It holds because the following instance of the rule body is provable:
1996
+ # (10 3) math:integerQuotient 3 .
1997
+ # 3 math:equalTo 3 .
1998
+ # via the schematic forward rule:
1999
+ # {
2000
+ # (10 3) math:integerQuotient ?q .
2001
+ # ?q math:equalTo 3 .
2002
+ # } => {
2003
+ # :test-integerQuotient-1 a :MathBuiltinTest .
2004
+ # :test-integerQuotient-1 :builtin math:integerQuotient .
2005
+ # :test-integerQuotient-1 :input (10 3) .
2006
+ # :test-integerQuotient-1 :expected 3 .
2007
+ # :test-integerQuotient-1 :actual ?q .
2008
+ # :test-integerQuotient-1 :status :pass .
2009
+ # } .
2010
+ # with substitution (on rule variables):
2011
+ # ?q = 3
2012
+ # Therefore the derived triple above is entailed by the rules and facts.
2013
+ # ----------------------------------------------------------------------
2014
+
2015
+ :test-integerQuotient-1 a :MathBuiltinTest .
2016
+
2017
+ # ----------------------------------------------------------------------
2018
+ # Proof for derived triple:
2019
+ # :test-integerQuotient-1 :builtin math:integerQuotient .
2020
+ # It holds because the following instance of the rule body is provable:
2021
+ # (10 3) math:integerQuotient 3 .
2022
+ # 3 math:equalTo 3 .
2023
+ # via the schematic forward rule:
2024
+ # {
2025
+ # (10 3) math:integerQuotient ?q .
2026
+ # ?q math:equalTo 3 .
2027
+ # } => {
2028
+ # :test-integerQuotient-1 a :MathBuiltinTest .
2029
+ # :test-integerQuotient-1 :builtin math:integerQuotient .
2030
+ # :test-integerQuotient-1 :input (10 3) .
2031
+ # :test-integerQuotient-1 :expected 3 .
2032
+ # :test-integerQuotient-1 :actual ?q .
2033
+ # :test-integerQuotient-1 :status :pass .
2034
+ # } .
2035
+ # with substitution (on rule variables):
2036
+ # ?q = 3
2037
+ # Therefore the derived triple above is entailed by the rules and facts.
2038
+ # ----------------------------------------------------------------------
2039
+
2040
+ :test-integerQuotient-1 :builtin math:integerQuotient .
2041
+
2042
+ # ----------------------------------------------------------------------
2043
+ # Proof for derived triple:
2044
+ # :test-integerQuotient-1 :input (10 3) .
2045
+ # It holds because the following instance of the rule body is provable:
2046
+ # (10 3) math:integerQuotient 3 .
2047
+ # 3 math:equalTo 3 .
2048
+ # via the schematic forward rule:
2049
+ # {
2050
+ # (10 3) math:integerQuotient ?q .
2051
+ # ?q math:equalTo 3 .
2052
+ # } => {
2053
+ # :test-integerQuotient-1 a :MathBuiltinTest .
2054
+ # :test-integerQuotient-1 :builtin math:integerQuotient .
2055
+ # :test-integerQuotient-1 :input (10 3) .
2056
+ # :test-integerQuotient-1 :expected 3 .
2057
+ # :test-integerQuotient-1 :actual ?q .
2058
+ # :test-integerQuotient-1 :status :pass .
2059
+ # } .
2060
+ # with substitution (on rule variables):
2061
+ # ?q = 3
2062
+ # Therefore the derived triple above is entailed by the rules and facts.
2063
+ # ----------------------------------------------------------------------
2064
+
2065
+ :test-integerQuotient-1 :input (10 3) .
2066
+
2067
+ # ----------------------------------------------------------------------
2068
+ # Proof for derived triple:
2069
+ # :test-integerQuotient-1 :expected 3 .
2070
+ # It holds because the following instance of the rule body is provable:
2071
+ # (10 3) math:integerQuotient 3 .
2072
+ # 3 math:equalTo 3 .
2073
+ # via the schematic forward rule:
2074
+ # {
2075
+ # (10 3) math:integerQuotient ?q .
2076
+ # ?q math:equalTo 3 .
2077
+ # } => {
2078
+ # :test-integerQuotient-1 a :MathBuiltinTest .
2079
+ # :test-integerQuotient-1 :builtin math:integerQuotient .
2080
+ # :test-integerQuotient-1 :input (10 3) .
2081
+ # :test-integerQuotient-1 :expected 3 .
2082
+ # :test-integerQuotient-1 :actual ?q .
2083
+ # :test-integerQuotient-1 :status :pass .
2084
+ # } .
2085
+ # with substitution (on rule variables):
2086
+ # ?q = 3
2087
+ # Therefore the derived triple above is entailed by the rules and facts.
2088
+ # ----------------------------------------------------------------------
2089
+
2090
+ :test-integerQuotient-1 :expected 3 .
2091
+
2092
+ # ----------------------------------------------------------------------
2093
+ # Proof for derived triple:
2094
+ # :test-integerQuotient-1 :actual 3 .
2095
+ # It holds because the following instance of the rule body is provable:
2096
+ # (10 3) math:integerQuotient 3 .
2097
+ # 3 math:equalTo 3 .
2098
+ # via the schematic forward rule:
2099
+ # {
2100
+ # (10 3) math:integerQuotient ?q .
2101
+ # ?q math:equalTo 3 .
2102
+ # } => {
2103
+ # :test-integerQuotient-1 a :MathBuiltinTest .
2104
+ # :test-integerQuotient-1 :builtin math:integerQuotient .
2105
+ # :test-integerQuotient-1 :input (10 3) .
2106
+ # :test-integerQuotient-1 :expected 3 .
2107
+ # :test-integerQuotient-1 :actual ?q .
2108
+ # :test-integerQuotient-1 :status :pass .
2109
+ # } .
2110
+ # with substitution (on rule variables):
2111
+ # ?q = 3
2112
+ # Therefore the derived triple above is entailed by the rules and facts.
2113
+ # ----------------------------------------------------------------------
2114
+
2115
+ :test-integerQuotient-1 :actual 3 .
2116
+
2117
+ # ----------------------------------------------------------------------
2118
+ # Proof for derived triple:
2119
+ # :test-integerQuotient-1 :status :pass .
2120
+ # It holds because the following instance of the rule body is provable:
2121
+ # (10 3) math:integerQuotient 3 .
2122
+ # 3 math:equalTo 3 .
2123
+ # via the schematic forward rule:
2124
+ # {
2125
+ # (10 3) math:integerQuotient ?q .
2126
+ # ?q math:equalTo 3 .
2127
+ # } => {
2128
+ # :test-integerQuotient-1 a :MathBuiltinTest .
2129
+ # :test-integerQuotient-1 :builtin math:integerQuotient .
2130
+ # :test-integerQuotient-1 :input (10 3) .
2131
+ # :test-integerQuotient-1 :expected 3 .
2132
+ # :test-integerQuotient-1 :actual ?q .
2133
+ # :test-integerQuotient-1 :status :pass .
2134
+ # } .
2135
+ # with substitution (on rule variables):
2136
+ # ?q = 3
2137
+ # Therefore the derived triple above is entailed by the rules and facts.
2138
+ # ----------------------------------------------------------------------
2139
+
2140
+ :test-integerQuotient-1 :status :pass .
2141
+
1992
2142
  # ----------------------------------------------------------------------
1993
2143
  # Proof for derived triple:
1994
2144
  # :test-lessThan-1 a :MathBuiltinTest .
package/eyeling.js CHANGED
@@ -676,8 +676,23 @@ class Parser {
676
676
  this.expectDot();
677
677
  backwardRules.push(this.makeRule(first, second, false));
678
678
  } else {
679
- const more = this.parsePredicateObjectList(first);
680
- this.expectDot();
679
+ let more;
680
+
681
+ if (this.peek().typ === "Dot") {
682
+ // Allow a bare blank-node property list statement, e.g. `[ a :Statement ].`
683
+ const lastTok = this.toks[this.pos - 1];
684
+ if (this.pendingTriples.length > 0 && lastTok && lastTok.typ === "RBracket") {
685
+ more = this.pendingTriples;
686
+ this.pendingTriples = [];
687
+ this.next(); // consume '.'
688
+ } else {
689
+ throw new Error(`Unexpected '.' after term; missing predicate/object list`);
690
+ }
691
+ } else {
692
+ more = this.parsePredicateObjectList(first);
693
+ this.expectDot();
694
+ }
695
+
681
696
  // normalize explicit log:implies / log:impliedBy at top-level
682
697
  for (const tr of more) {
683
698
  if (isLogImplies(tr.p) && tr.s instanceof FormulaTerm && tr.o instanceof FormulaTerm) {
@@ -692,7 +707,6 @@ class Parser {
692
707
  }
693
708
  }
694
709
 
695
- // console.log(JSON.stringify([this.prefixes, triples, forwardRules, backwardRules], null, 2));
696
710
  return [this.prefixes, triples, forwardRules, backwardRules];
697
711
  }
698
712
 
@@ -929,6 +943,17 @@ class Parser {
929
943
  throw new Error(`Expected '.' or '}', got ${this.peek().toString()}`);
930
944
  }
931
945
  } else {
946
+ // Allow a bare blank-node property list statement inside a formula, e.g. `{ [ a :X ]. }`
947
+ if (this.peek().typ === "Dot" || this.peek().typ === "RBrace") {
948
+ const lastTok = this.toks[this.pos - 1];
949
+ if (this.pendingTriples.length > 0 && lastTok && lastTok.typ === "RBracket") {
950
+ triples.push(...this.pendingTriples);
951
+ this.pendingTriples = [];
952
+ if (this.peek().typ === "Dot") this.next();
953
+ continue;
954
+ }
955
+ }
956
+
932
957
  triples.push(...this.parsePredicateObjectList(left));
933
958
  if (this.peek().typ === "Dot") this.next();
934
959
  else if (this.peek().typ === "RBrace") {
@@ -4187,6 +4212,7 @@ function main() {
4187
4212
  const toks = lex(text);
4188
4213
  const parser = new Parser(toks);
4189
4214
  const [prefixes, triples, frules, brules] = parser.parseDocument();
4215
+ // console.log(JSON.stringify([prefixes, triples, frules, brules], null, 2));
4190
4216
 
4191
4217
  const facts = triples.filter(tr => isGroundTriple(tr));
4192
4218
  const derived = forwardChain(facts, frules, brules);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.5.29",
3
+ "version": "1.5.31",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [