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 +37 -39
- package/examples/math-builtins-tests.n3 +11 -0
- package/examples/output/math-builtins-tests.n3 +150 -0
- package/eyeling.js +29 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -98,10 +98,10 @@ npm run test:package
|
|
|
98
98
|
npm run test:packlist
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
-
|
|
150
|
-
|
|
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
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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
|
-
|
|
198
|
-
|
|
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
|
-
|
|
217
|
-
|
|
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
|
-
|
|
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
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
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
|
-
|
|
680
|
-
|
|
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);
|