@skaterqiang/protege-js 0.1.0
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/CHANGELOG.md +65 -0
- package/LICENSE +48 -0
- package/README.md +287 -0
- package/docs/API.md +654 -0
- package/docs/design/OWL2-/347/274/272/345/217/243/345/210/206/346/236/220.md +140 -0
- package/docs/owl2-rl/OWL2-RL-/350/247/204/345/210/231/347/273/206/345/210/231.md +168 -0
- package/docs/owl2-rl/owl2-profiles-spec-zh.html +1914 -0
- package/docs/owl2-rl/owl2-profiles-spec.html +1916 -0
- package/docs/owl2-rl/rl_rules.json +392 -0
- package/main.js +46 -0
- package/package.json +76 -0
- package/sample/README.md +74 -0
- package/sample/case1-ecommerce-risk.js +170 -0
- package/sample/case10-ecommerce-customer-service.js +454 -0
- package/sample/case2-family-swrl.js +147 -0
- package/sample/case3-pharma-safety.js +132 -0
- package/sample/case4-knowledge-publishing.js +111 -0
- package/sample/case5-obda-profiles.js +153 -0
- package/sample/case6-medical-ontology.js +152 -0
- package/sample/case7-manufacturing-ppr.js +155 -0
- package/sample/case8-real-medical-bfo-ogms.js +353 -0
- package/sample/case9-real-manufacturing-iao.js +360 -0
- package/sample/ontologies/bfo.owl +1715 -0
- package/sample/ontologies/iao.owl +8532 -0
- package/sample/ontologies/ogms.owl +4320 -0
- package/sample/ontologies/ro-core.owl +1010 -0
- package/scripts/verify-api.js +53 -0
- package/src/index.js +176 -0
- package/src/inference/OWL2ProfileReasoners.js +67 -0
- package/src/inference/OWL2RLReasoner.js +65 -0
- package/src/inference/ReasonerQueries.js +111 -0
- package/src/inference/SWRLReasoner.js +409 -0
- package/src/inference/TripleStore.js +82 -0
- package/src/inference/rdf.js +83 -0
- package/src/inference/rules/owl2el.js +33 -0
- package/src/inference/rules/owl2ql.js +29 -0
- package/src/inference/rules/owl2rl.js +823 -0
- package/src/io/FunctionalSyntaxParser.js +399 -0
- package/src/io/FunctionalSyntaxWriter.js +180 -0
- package/src/io/ManchesterSyntaxParser.js +398 -0
- package/src/io/OWLXMLParser.js +356 -0
- package/src/io/OntologyLoader.js +125 -0
- package/src/io/RDFGraphToOntology.js +702 -0
- package/src/io/RDFXMLParser.js +319 -0
- package/src/io/RDFXMLWriter.js +196 -0
- package/src/io/SWRLParser.js +150 -0
- package/src/io/TurtleParser.js +363 -0
- package/src/io/TurtleWriter.js +393 -0
- package/src/model/IRI.js +62 -0
- package/src/model/OWLAxiom.js +507 -0
- package/src/model/OWLClassExpression.js +242 -0
- package/src/model/OWLEntity.js +142 -0
- package/src/model/OWLLiteral.js +30 -0
- package/src/model/OWLModelManager.js +106 -0
- package/src/model/OWLOntology.js +119 -0
- package/src/model/SWRL.js +152 -0
- package/src/model/event/OWLModelManagerEvent.js +33 -0
- package/src/model/hierarchy/HierarchyProvider.js +214 -0
- package/src/profiles/OWL2Profiles.js +185 -0
- package/src/server/public/app.js +97 -0
- package/src/server/public/index.html +49 -0
- package/src/server/webServer.js +138 -0
- package/src/validation/GlobalRestrictionsValidator.js +172 -0
- package/test/core.test.js +111 -0
- package/test/exports-map.test.js +165 -0
- package/test/owl2/axioms.test.js +160 -0
- package/test/owl2/classExpressions.test.js +99 -0
- package/test/owl2/functional-syntax-writer.test.js +65 -0
- package/test/owl2/functional.test.js +113 -0
- package/test/owl2/global-restrictions.test.js +76 -0
- package/test/owl2/longtail.test.js +74 -0
- package/test/owl2/manchester-syntax.test.js +100 -0
- package/test/owl2/ontology-loader-imports.test.js +62 -0
- package/test/owl2/owlxml-parser.test.js +112 -0
- package/test/owl2/profile-reasoners.test.js +108 -0
- package/test/owl2/profiles.test.js +66 -0
- package/test/owl2/rdf-graph-to-ontology.test.js +177 -0
- package/test/owl2/rdfxml-punning.test.js +25 -0
- package/test/owl2/rdfxml-writer.test.js +55 -0
- package/test/owl2/rdfxml.test.js +91 -0
- package/test/owl2/reasoner-queries.test.js +58 -0
- package/test/owl2/sample-e2e.test.js +195 -0
- package/test/owl2/swrl-parser.test.js +60 -0
- package/test/owl2/swrl.test.js +131 -0
- package/test/owl2/turtle-writer.test.js +84 -0
- package/test/owl2/turtle.test.js +124 -0
- package/test/owl2rl/cax.test.js +57 -0
- package/test/owl2rl/cls.test.js +210 -0
- package/test/owl2rl/dt.test.js +72 -0
- package/test/owl2rl/eq.test.js +95 -0
- package/test/owl2rl/prp.test.js +198 -0
- package/test/owl2rl/scm.test.js +203 -0
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// io/ManchesterSyntaxParser — parse OWL 2 Manchester Syntax (frame-style).
|
|
5
|
+
// Mirrors the syntax used by Protégé's "Manchester Syntax" rendering:
|
|
6
|
+
//
|
|
7
|
+
// Class: ex:Person
|
|
8
|
+
// SubClassOf: ex:Animal
|
|
9
|
+
// SubClassOf: ex:hasParent some ex:Person
|
|
10
|
+
// EquivalentTo: ex:Human
|
|
11
|
+
// DisjointWith: ex:Robot
|
|
12
|
+
// DisjointUnionOf: ex:Child, ex:Adult
|
|
13
|
+
//
|
|
14
|
+
// ObjectProperty: ex:hasParent
|
|
15
|
+
// Domain: ex:Person
|
|
16
|
+
// Range: ex:Person
|
|
17
|
+
// Characteristics: Transitive, Functional
|
|
18
|
+
// InverseOf: ex:hasChild
|
|
19
|
+
// SubPropertyOf: ex:hasAncestor
|
|
20
|
+
//
|
|
21
|
+
// Individual: ex:alice
|
|
22
|
+
// Types: ex:Person
|
|
23
|
+
// Facts: ex:hasParent ex:bob
|
|
24
|
+
// SameAs: ex:alicia
|
|
25
|
+
//
|
|
26
|
+
// Class expressions use: and / or / not / some / only / value / Self /
|
|
27
|
+
// min n / max n / exactly n / {ind1, ind2}
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
const { OWLOntology, OWLOntologyID } = require('../model/OWLOntology');
|
|
31
|
+
const {
|
|
32
|
+
OWLClass, OWLObjectProperty, OWLDataProperty, OWLNamedIndividual, OWLDatatype
|
|
33
|
+
} = require('../model/OWLEntity');
|
|
34
|
+
const AX = require('../model/OWLAxiom');
|
|
35
|
+
const CE = require('../model/OWLClassExpression');
|
|
36
|
+
const { OWLLiteral } = require('../model/OWLLiteral');
|
|
37
|
+
const { IRI } = require('../model/IRI');
|
|
38
|
+
|
|
39
|
+
const XSD = 'http://www.w3.org/2001/XMLSchema#';
|
|
40
|
+
|
|
41
|
+
const DEFAULT_PREFIXES = {
|
|
42
|
+
rdf: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
|
|
43
|
+
rdfs: 'http://www.w3.org/2000/01/rdf-schema#',
|
|
44
|
+
owl: 'http://www.w3.org/2002/07/owl#',
|
|
45
|
+
xsd: XSD
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
class ManchesterSyntaxParser {
|
|
49
|
+
constructor(opts = {}) {
|
|
50
|
+
this.prefixes = Object.assign({}, DEFAULT_PREFIXES, opts.prefixes || {});
|
|
51
|
+
this.base = opts.base || 'http://example.org/';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
expandIRI(token) {
|
|
55
|
+
if (token.startsWith('<') && token.endsWith('>')) return token.slice(1, -1);
|
|
56
|
+
if (token.startsWith('http://') || token.startsWith('https://') || token.startsWith('urn:')) return token;
|
|
57
|
+
const idx = token.indexOf(':');
|
|
58
|
+
if (idx > 0) {
|
|
59
|
+
const ns = this.prefixes[token.slice(0, idx)];
|
|
60
|
+
if (ns) return ns + token.slice(idx + 1);
|
|
61
|
+
}
|
|
62
|
+
return this.base + token;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Parse Manchester Syntax text into an OWLOntology.
|
|
67
|
+
* @param {string} text
|
|
68
|
+
* @returns {OWLOntology}
|
|
69
|
+
*/
|
|
70
|
+
parse(text, ontologyIRI = null) {
|
|
71
|
+
const ont = new OWLOntology(new OWLOntologyID(ontologyIRI ? IRI.create(ontologyIRI) : null));
|
|
72
|
+
ont.format = 'Manchester';
|
|
73
|
+
|
|
74
|
+
// Parse Prefix: lines first
|
|
75
|
+
const lines = text.split(/\r?\n/);
|
|
76
|
+
const contentLines = [];
|
|
77
|
+
for (const line of lines) {
|
|
78
|
+
const m = /^Prefix:\s*([\w-]*):?\s*<([^>]+)>/.exec(line.trim());
|
|
79
|
+
if (m) {
|
|
80
|
+
this.prefixes[m[1] || ''] = m[2];
|
|
81
|
+
ont.addPrefix(m[1] || '', m[2]); // prefix fidelity (L5)
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
contentLines.push(line);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Split into frames by "Class:" / "ObjectProperty:" / "DataProperty:" /
|
|
88
|
+
// "Individual:" / "Datatype:" / "AnnotationProperty:" headers
|
|
89
|
+
let frame = null;
|
|
90
|
+
for (const raw of contentLines) {
|
|
91
|
+
const line = raw;
|
|
92
|
+
if (!line.trim()) continue;
|
|
93
|
+
const fm = /^(Class|ObjectProperty|DataProperty|Individual|Datatype|AnnotationProperty):\s*(\S+)/.exec(line);
|
|
94
|
+
if (fm && !/^\s/.test(line)) {
|
|
95
|
+
frame = { kind: fm[1], iri: this.expandIRI(fm[2]) };
|
|
96
|
+
this._declareFrame(ont, frame);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (frame) {
|
|
100
|
+
this._frameLine(ont, frame, line.trim());
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return ont;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
_declareFrame(ont, frame) {
|
|
107
|
+
const mk = {
|
|
108
|
+
Class: (i) => new OWLClass(i),
|
|
109
|
+
ObjectProperty: (i) => new OWLObjectProperty(i),
|
|
110
|
+
DataProperty: (i) => new OWLDataProperty(i),
|
|
111
|
+
Individual: (i) => new OWLNamedIndividual(i),
|
|
112
|
+
Datatype: (i) => new OWLDatatype(i),
|
|
113
|
+
AnnotationProperty: (i) => new (require('../model/OWLEntity').OWLAnnotationProperty)(i)
|
|
114
|
+
}[frame.kind];
|
|
115
|
+
if (mk) ont.addAxiom(new AX.OWLDeclarationAxiom(mk(frame.iri)));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
_frameLine(ont, frame, line) {
|
|
119
|
+
// Split on the FIRST colon only — values may contain prefixed IRIs (ex:Foo)
|
|
120
|
+
const ci = line.indexOf(':');
|
|
121
|
+
const keyword = (ci >= 0 ? line.slice(0, ci) : line).trim();
|
|
122
|
+
const body = (ci >= 0 ? line.slice(ci + 1) : '').trim();
|
|
123
|
+
if (!body) return;
|
|
124
|
+
const items = splitTopLevel(body, ',');
|
|
125
|
+
|
|
126
|
+
switch (frame.kind) {
|
|
127
|
+
case 'Class': {
|
|
128
|
+
const cls = new OWLClass(frame.iri);
|
|
129
|
+
if (keyword === 'SubClassOf') {
|
|
130
|
+
for (const it of items) ont.addAxiom(new AX.OWLSubClassOfAxiom(cls, this._classExpr(it)));
|
|
131
|
+
} else if (keyword === 'EquivalentTo') {
|
|
132
|
+
// Keep {a,b,c} enumeration as ONE item
|
|
133
|
+
for (const it of items) ont.addAxiom(new AX.OWLEquivalentClassesAxiom([cls, this._classExpr(it)]));
|
|
134
|
+
} else if (keyword === 'DisjointWith') {
|
|
135
|
+
for (const it of items) ont.addAxiom(new AX.OWLDisjointClassesAxiom([cls, this._classExpr(it)]));
|
|
136
|
+
} else if (keyword === 'DisjointUnionOf') {
|
|
137
|
+
ont.addAxiom(new AX.OWLDisjointUnionAxiom(cls, items.map(i => this._classExpr(i))));
|
|
138
|
+
} else if (keyword === 'HasKey') {
|
|
139
|
+
const props = items.map(i => new OWLObjectProperty(this.expandIRI(i.trim())));
|
|
140
|
+
ont.addAxiom(new AX.OWLHasKeyAxiom(cls, props));
|
|
141
|
+
}
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
case 'ObjectProperty': {
|
|
145
|
+
const p = new OWLObjectProperty(frame.iri);
|
|
146
|
+
if (keyword === 'SubPropertyOf') {
|
|
147
|
+
for (const it of items) ont.addAxiom(new AX.OWLSubObjectPropertyOfAxiom(p, new OWLObjectProperty(this.expandIRI(it))));
|
|
148
|
+
} else if (keyword === 'Domain') {
|
|
149
|
+
for (const it of items) ont.addAxiom(new AX.OWLObjectPropertyDomainAxiom(p, this._classExpr(it)));
|
|
150
|
+
} else if (keyword === 'Range') {
|
|
151
|
+
for (const it of items) ont.addAxiom(new AX.OWLObjectPropertyRangeAxiom(p, this._classExpr(it)));
|
|
152
|
+
} else if (keyword === 'InverseOf') {
|
|
153
|
+
for (const it of items) ont.addAxiom(new AX.OWLInverseObjectPropertiesAxiom(p, new OWLObjectProperty(this.expandIRI(it))));
|
|
154
|
+
} else if (keyword === 'Characteristics') {
|
|
155
|
+
for (const c of items) {
|
|
156
|
+
const cc = c.trim();
|
|
157
|
+
const map = {
|
|
158
|
+
Functional: AX.OWLFunctionalObjectPropertyAxiom,
|
|
159
|
+
InverseFunctional: AX.OWLInverseFunctionalObjectPropertyAxiom,
|
|
160
|
+
Transitive: AX.OWLTransitiveObjectPropertyAxiom,
|
|
161
|
+
Symmetric: AX.OWLSymmetricObjectPropertyAxiom,
|
|
162
|
+
Asymmetric: AX.OWLAsymmetricObjectPropertyAxiom,
|
|
163
|
+
Reflexive: AX.OWLReflexiveObjectPropertyAxiom,
|
|
164
|
+
Irreflexive: AX.OWLIrreflexiveObjectPropertyAxiom
|
|
165
|
+
};
|
|
166
|
+
if (map[cc]) ont.addAxiom(new map[cc](p));
|
|
167
|
+
}
|
|
168
|
+
} else if (keyword === 'SubPropertyChain') {
|
|
169
|
+
const chain = body.split(/\s*o\s*/).map(s => new OWLObjectProperty(this.expandIRI(s.trim())));
|
|
170
|
+
ont.addAxiom(new AX.OWLSubPropertyChainOfAxiom(chain, p));
|
|
171
|
+
}
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
case 'DataProperty': {
|
|
175
|
+
const p = new OWLDataProperty(frame.iri);
|
|
176
|
+
if (keyword === 'SubPropertyOf') {
|
|
177
|
+
for (const it of items) ont.addAxiom(new AX.OWLSubDataPropertyOfAxiom(p, new OWLDataProperty(this.expandIRI(it))));
|
|
178
|
+
} else if (keyword === 'Domain') {
|
|
179
|
+
for (const it of items) ont.addAxiom(new AX.OWLDataPropertyDomainAxiom(p, this._classExpr(it)));
|
|
180
|
+
} else if (keyword === 'Range') {
|
|
181
|
+
for (const it of items) ont.addAxiom(new AX.OWLDataPropertyRangeAxiom(p, new OWLDatatype(this.expandIRI(it))));
|
|
182
|
+
} else if (keyword === 'Characteristics') {
|
|
183
|
+
if (items.some(c => c.trim() === 'Functional')) {
|
|
184
|
+
ont.addAxiom(new AX.OWLFunctionalDataPropertyAxiom(p));
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
case 'Individual': {
|
|
190
|
+
const ind = new OWLNamedIndividual(frame.iri);
|
|
191
|
+
if (keyword === 'Types') {
|
|
192
|
+
for (const it of items) ont.addAxiom(new AX.OWLClassAssertionAxiom(ind, this._classExpr(it)));
|
|
193
|
+
} else if (keyword === 'SameAs') {
|
|
194
|
+
for (const it of items) ont.addAxiom(new AX.OWLSameIndividualAxiom([ind, new OWLNamedIndividual(this.expandIRI(it))]));
|
|
195
|
+
} else if (keyword === 'DifferentFrom') {
|
|
196
|
+
for (const it of items) ont.addAxiom(new AX.OWLDifferentIndividualsAxiom([ind, new OWLNamedIndividual(this.expandIRI(it))]));
|
|
197
|
+
} else if (keyword === 'Facts') {
|
|
198
|
+
// "Facts: p target, q target2"
|
|
199
|
+
for (const it of items) {
|
|
200
|
+
const m = /^(\S+)\s+(\S+)$/.exec(it.trim());
|
|
201
|
+
if (!m) continue;
|
|
202
|
+
const pIRI = this.expandIRI(m[1]);
|
|
203
|
+
const tgt = m[2];
|
|
204
|
+
if (tgt.startsWith('"')) {
|
|
205
|
+
ont.addAxiom(new AX.OWLDataPropertyAssertionAxiom(
|
|
206
|
+
ind, new OWLDataProperty(pIRI), this._literal(tgt)));
|
|
207
|
+
} else {
|
|
208
|
+
ont.addAxiom(new AX.OWLObjectPropertyAssertionAxiom(
|
|
209
|
+
ind, new OWLObjectProperty(pIRI), new OWLNamedIndividual(this.expandIRI(tgt))));
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// --- class expression (Manchester infix) ----------------------------------
|
|
219
|
+
|
|
220
|
+
_classExpr(text) {
|
|
221
|
+
const tokens = this._tokenizeExpr(text);
|
|
222
|
+
this._toks = tokens;
|
|
223
|
+
this._pos = 0;
|
|
224
|
+
const e = this._orExpr();
|
|
225
|
+
return e;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
_tokenizeExpr(s) {
|
|
229
|
+
const out = [];
|
|
230
|
+
let i = 0;
|
|
231
|
+
while (i < s.length) {
|
|
232
|
+
const ch = s[i];
|
|
233
|
+
if (/\s/.test(ch)) { i++; continue; }
|
|
234
|
+
if (ch === '(' || ch === ')' || ch === '{' || ch === '}' || ch === ',') { out.push(ch); i++; continue; }
|
|
235
|
+
if (ch === '"') {
|
|
236
|
+
let j = i + 1, v = '';
|
|
237
|
+
while (j < s.length && s[j] !== '"') { v += s[j]; j++; }
|
|
238
|
+
out.push({ lit: v });
|
|
239
|
+
i = j + 1;
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
let j = i;
|
|
243
|
+
while (j < s.length && /[^\s(),{}]/.test(s[j])) j++;
|
|
244
|
+
out.push(s.slice(i, j));
|
|
245
|
+
i = j;
|
|
246
|
+
}
|
|
247
|
+
return out;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
_peekT() { return this._toks[this._pos]; }
|
|
251
|
+
_nextT() { return this._toks[this._pos++]; }
|
|
252
|
+
|
|
253
|
+
_orExpr() {
|
|
254
|
+
let e = this._andExpr();
|
|
255
|
+
while (this._peekT() === 'or') {
|
|
256
|
+
this._nextT();
|
|
257
|
+
const rhs = this._andExpr();
|
|
258
|
+
e = new CE.OWLObjectUnionOf(flatten(e, T => T.OBJECT_UNION_OF).concat(flatten(rhs, T => T.OBJECT_UNION_OF)));
|
|
259
|
+
}
|
|
260
|
+
return e;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
_andExpr() {
|
|
264
|
+
let e = this._unaryExpr();
|
|
265
|
+
while (this._peekT() === 'and') {
|
|
266
|
+
this._nextT();
|
|
267
|
+
const rhs = this._unaryExpr();
|
|
268
|
+
e = new CE.OWLObjectIntersectionOf(flatten(e, T => T.OBJECT_INTERSECTION_OF).concat(flatten(rhs, T => T.OBJECT_INTERSECTION_OF)));
|
|
269
|
+
}
|
|
270
|
+
return e;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
_unaryExpr() {
|
|
274
|
+
if (this._peekT() === 'not') {
|
|
275
|
+
this._nextT();
|
|
276
|
+
return new CE.OWLObjectComplementOf(this._unaryExpr());
|
|
277
|
+
}
|
|
278
|
+
return this._restrictionExpr();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
_restrictionExpr() {
|
|
282
|
+
const t = this._peekT();
|
|
283
|
+
// Property-based restriction: <prop> (some|only|value|Self|min|max|exactly) ...
|
|
284
|
+
if (typeof t === 'string' && t !== '(' && t !== '{') {
|
|
285
|
+
const next = this._toks[this._pos + 1];
|
|
286
|
+
if (typeof next === 'string' && /^(some|only|value|Self|min|max|exactly)$/.test(next)) {
|
|
287
|
+
const propTok = this._nextT();
|
|
288
|
+
const propIRI = this.expandIRI(propTok);
|
|
289
|
+
const kw = this._nextT();
|
|
290
|
+
const prop = new OWLObjectProperty(propIRI);
|
|
291
|
+
if (kw === 'some') return new CE.OWLObjectSomeValuesFrom(prop, this._unaryExpr());
|
|
292
|
+
if (kw === 'only') return new CE.OWLObjectAllValuesFrom(prop, this._unaryExpr());
|
|
293
|
+
if (kw === 'value') {
|
|
294
|
+
const indTok = this._nextT();
|
|
295
|
+
return new CE.OWLObjectHasValue(prop, new OWLNamedIndividual(this.expandIRI(typeof indTok === 'object' ? indTok.lit : indTok)));
|
|
296
|
+
}
|
|
297
|
+
if (kw === 'Self') return new CE.OWLObjectHasSelf(prop);
|
|
298
|
+
if (kw === 'min' || kw === 'max' || kw === 'exactly') {
|
|
299
|
+
const n = parseInt(this._nextT(), 10);
|
|
300
|
+
// Optional filler — only consume if next token is NOT a frame keyword
|
|
301
|
+
// or a closing bracket/comma. In Manchester, `min 2 ex:Foo` has filler;
|
|
302
|
+
// `min 2` alone is unqualified.
|
|
303
|
+
let filler = null;
|
|
304
|
+
const nt = this._peekT();
|
|
305
|
+
if (nt !== undefined && nt !== ')' && nt !== ',' && nt !== 'and' && nt !== 'or') {
|
|
306
|
+
filler = this._unaryExpr();
|
|
307
|
+
}
|
|
308
|
+
const T = CE.ClassExpressionType;
|
|
309
|
+
const type = kw === 'min' ? (filler ? T.OBJECT_MIN_QUALIFIED_CARDINALITY : T.OBJECT_MIN_CARDINALITY)
|
|
310
|
+
: kw === 'max' ? (filler ? T.OBJECT_MAX_QUALIFIED_CARDINALITY : T.OBJECT_MAX_CARDINALITY)
|
|
311
|
+
: (filler ? T.OBJECT_EXACT_QUALIFIED_CARDINALITY : T.OBJECT_EXACT_CARDINALITY);
|
|
312
|
+
return new CE.OWLObjectCardinalityRestriction(type, n, prop, filler);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return this._primary();
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
_primary() {
|
|
320
|
+
const t = this._peekT();
|
|
321
|
+
if (t === '(') {
|
|
322
|
+
this._nextT();
|
|
323
|
+
const e = this._orExpr();
|
|
324
|
+
if (this._peekT() === ')') this._nextT();
|
|
325
|
+
return e;
|
|
326
|
+
}
|
|
327
|
+
if (t === '{') {
|
|
328
|
+
this._nextT();
|
|
329
|
+
const inds = [];
|
|
330
|
+
while (this._peekT() !== '}' && this._peekT() !== undefined) {
|
|
331
|
+
const tok = this._nextT();
|
|
332
|
+
if (tok === ',') continue;
|
|
333
|
+
inds.push(new OWLNamedIndividual(this.expandIRI(typeof tok === 'object' ? tok.lit : tok)));
|
|
334
|
+
}
|
|
335
|
+
if (this._peekT() === '}') this._nextT();
|
|
336
|
+
return new CE.OWLObjectOneOf(inds);
|
|
337
|
+
}
|
|
338
|
+
const tok = this._nextT();
|
|
339
|
+
if (typeof tok === 'object' && tok.lit !== undefined) {
|
|
340
|
+
return new OWLLiteral(tok.lit);
|
|
341
|
+
}
|
|
342
|
+
return new OWLClass(this.expandIRI(tok));
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
_restOfPrimary() {
|
|
346
|
+
// Re-assemble remaining primary tokens until a natural stop (and/or/','/')')
|
|
347
|
+
const parts = [];
|
|
348
|
+
let depth = 0;
|
|
349
|
+
while (this._pos < this._toks.length) {
|
|
350
|
+
const t = this._peekT();
|
|
351
|
+
if (t === '(') depth++;
|
|
352
|
+
if (t === ')') { if (depth === 0) break; depth--; }
|
|
353
|
+
if (depth === 0 && (t === 'and' || t === 'or' || t === ',')) break;
|
|
354
|
+
parts.push(this._nextT());
|
|
355
|
+
}
|
|
356
|
+
// Parse collected tokens as a class expression by re-tokenizing
|
|
357
|
+
return this._classExprFromTokens(parts);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
_classExprFromTokens(tokens) {
|
|
361
|
+
const savedToks = this._toks, savedPos = this._pos;
|
|
362
|
+
this._toks = tokens; this._pos = 0;
|
|
363
|
+
const e = this._orExpr();
|
|
364
|
+
this._toks = savedToks; this._pos = savedPos;
|
|
365
|
+
return e;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
_literal(token) {
|
|
369
|
+
const m = /^"((?:[^"\\]|\\.)*)"(?:\^\^(.+))?$/.exec(token.trim());
|
|
370
|
+
if (!m) return new OWLLiteral(token.replace(/^"|"$/g, ''));
|
|
371
|
+
let dt = null;
|
|
372
|
+
if (m[2]) dt = new OWLDatatype(this.expandIRI(m[2]));
|
|
373
|
+
return new OWLLiteral(m[1], dt);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function flatten(expr, typeFn) {
|
|
378
|
+
const T = require('../model/OWLClassExpression').ClassExpressionType;
|
|
379
|
+
if (expr && expr.type && (expr.type === T.OBJECT_UNION_OF || expr.type === T.OBJECT_INTERSECTION_OF)) {
|
|
380
|
+
return expr.operands;
|
|
381
|
+
}
|
|
382
|
+
return [expr];
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function splitTopLevel(s, sep) {
|
|
386
|
+
const out = [];
|
|
387
|
+
let depth = 0, cur = '';
|
|
388
|
+
for (const ch of s) {
|
|
389
|
+
if (ch === '(' || ch === '{') depth++;
|
|
390
|
+
if (ch === ')' || ch === '}') depth--;
|
|
391
|
+
if (ch === sep && depth === 0) { out.push(cur.trim()); cur = ''; continue; }
|
|
392
|
+
cur += ch;
|
|
393
|
+
}
|
|
394
|
+
if (cur.trim()) out.push(cur.trim());
|
|
395
|
+
return out;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
module.exports = { ManchesterSyntaxParser };
|