@stevenvo780/st-lang 2.8.0 → 3.0.1
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/dist/ast/nodes.d.ts +35 -2
- package/dist/ast/nodes.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/lexer/lexer.d.ts.map +1 -1
- package/dist/lexer/lexer.js +4 -0
- package/dist/lexer/lexer.js.map +1 -1
- package/dist/lexer/tokens.d.ts +8 -0
- package/dist/lexer/tokens.d.ts.map +1 -1
- package/dist/lexer/tokens.js +23 -0
- package/dist/lexer/tokens.js.map +1 -1
- package/dist/parser/parser.d.ts +6 -0
- package/dist/parser/parser.d.ts.map +1 -1
- package/dist/parser/parser.js +171 -6
- package/dist/parser/parser.js.map +1 -1
- package/dist/protocol/handler.d.ts.map +1 -1
- package/dist/protocol/handler.js +327 -88
- package/dist/protocol/handler.js.map +1 -1
- package/dist/runtime/interpreter.d.ts +24 -0
- package/dist/runtime/interpreter.d.ts.map +1 -1
- package/dist/runtime/interpreter.js +409 -1
- package/dist/runtime/interpreter.js.map +1 -1
- package/dist/tests/v3-features.test.d.ts +2 -0
- package/dist/tests/v3-features.test.d.ts.map +1 -0
- package/dist/tests/v3-features.test.js +529 -0
- package/dist/tests/v3-features.test.js.map +1 -0
- package/dist/tests/v3-stress.test.d.ts +2 -0
- package/dist/tests/v3-stress.test.d.ts.map +1 -0
- package/dist/tests/v3-stress.test.js +755 -0
- package/dist/tests/v3-stress.test.js.map +1 -0
- package/dist/text-layer/compiler.d.ts +4 -1
- package/dist/text-layer/compiler.d.ts.map +1 -1
- package/dist/text-layer/compiler.js +35 -0
- package/dist/text-layer/compiler.js.map +1 -1
- package/dist/types/index.d.ts +27 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,755 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ============================================================
|
|
3
|
+
// Tests v3 Stress — Cross-profile, combinatorial, edge cases
|
|
4
|
+
// Validates v3 features (define, unfold, fold, source,
|
|
5
|
+
// interpret, glossary, render) across ALL 11 logic profiles
|
|
6
|
+
// and under syntactic stress.
|
|
7
|
+
// ============================================================
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
const vitest_1 = require("vitest");
|
|
10
|
+
const interpreter_1 = require("../runtime/interpreter");
|
|
11
|
+
// ── Helpers ──────────────────────────────────────────────────
|
|
12
|
+
function run(source) {
|
|
13
|
+
const interp = new interpreter_1.Interpreter();
|
|
14
|
+
return interp.execute(source);
|
|
15
|
+
}
|
|
16
|
+
function runOk(source) {
|
|
17
|
+
const out = run(source);
|
|
18
|
+
if (out.exitCode !== 0) {
|
|
19
|
+
const errs = out.diagnostics
|
|
20
|
+
.filter((d) => d.severity === 'error')
|
|
21
|
+
.map((d) => `L${d.line}: ${d.message}`)
|
|
22
|
+
.join('\n');
|
|
23
|
+
throw new Error(`exitCode=${out.exitCode}\n${errs}\nstdout:\n${out.stdout}`);
|
|
24
|
+
}
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
// ── All profiles ─────────────────────────────────────────────
|
|
28
|
+
const ALL_PROFILES = [
|
|
29
|
+
'classical.propositional',
|
|
30
|
+
'classical.first_order',
|
|
31
|
+
'modal.k',
|
|
32
|
+
'paraconsistent.belnap',
|
|
33
|
+
'deontic.standard',
|
|
34
|
+
'epistemic.s5',
|
|
35
|
+
'aristotelian.syllogistic',
|
|
36
|
+
'intuitionistic.propositional',
|
|
37
|
+
'temporal.ltl',
|
|
38
|
+
'probabilistic.basic',
|
|
39
|
+
'arithmetic',
|
|
40
|
+
];
|
|
41
|
+
// Profiles that support standard propositional operators (P -> Q)
|
|
42
|
+
const PROPOSITIONAL_PROFILES = [
|
|
43
|
+
'classical.propositional',
|
|
44
|
+
'classical.first_order',
|
|
45
|
+
'modal.k',
|
|
46
|
+
'paraconsistent.belnap',
|
|
47
|
+
'deontic.standard',
|
|
48
|
+
'epistemic.s5',
|
|
49
|
+
'intuitionistic.propositional',
|
|
50
|
+
'temporal.ltl',
|
|
51
|
+
'probabilistic.basic',
|
|
52
|
+
];
|
|
53
|
+
// ============================================================
|
|
54
|
+
// 1. define — across ALL profiles
|
|
55
|
+
// ============================================================
|
|
56
|
+
(0, vitest_1.describe)('v3 cross-profile: define + glossary', () => {
|
|
57
|
+
for (const profile of ALL_PROFILES) {
|
|
58
|
+
(0, vitest_1.it)(`define + glossary works in ${profile}`, () => {
|
|
59
|
+
const formula = profile === 'arithmetic' ? '2 + 3' : 'P -> Q';
|
|
60
|
+
const out = runOk(`logic ${profile}\ndefine D := ${formula}\nglossary`);
|
|
61
|
+
(0, vitest_1.expect)(out.stdout).toContain('Define');
|
|
62
|
+
(0, vitest_1.expect)(out.stdout).toContain('GLOSARIO');
|
|
63
|
+
(0, vitest_1.expect)(out.stdout).toContain('D');
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
for (const profile of ALL_PROFILES) {
|
|
67
|
+
(0, vitest_1.it)(`define with description works in ${profile}`, () => {
|
|
68
|
+
const formula = profile === 'arithmetic' ? '2 + 3' : 'P -> Q';
|
|
69
|
+
const out = runOk(`logic ${profile}\ndefine D := ${formula}\ndescription "test desc"\nglossary`);
|
|
70
|
+
(0, vitest_1.expect)(out.stdout).toContain('test desc');
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
// ============================================================
|
|
75
|
+
// 2. define with params — propositional profiles
|
|
76
|
+
// ============================================================
|
|
77
|
+
(0, vitest_1.describe)('v3 cross-profile: parametric define', () => {
|
|
78
|
+
for (const profile of PROPOSITIONAL_PROFILES) {
|
|
79
|
+
(0, vitest_1.it)(`parametric define Impl(x,y) := x -> y in ${profile}`, () => {
|
|
80
|
+
const out = runOk(`logic ${profile}\ndefine Impl(x, y) := x -> y\nunfold Impl(P, Q)`);
|
|
81
|
+
(0, vitest_1.expect)(out.stdout).toContain('Unfold');
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
// ============================================================
|
|
86
|
+
// 3. define expansion in check valid — all profiles that
|
|
87
|
+
// recognize P -> P as valid
|
|
88
|
+
// ============================================================
|
|
89
|
+
(0, vitest_1.describe)('v3 cross-profile: define expansion in check valid', () => {
|
|
90
|
+
// P -> P is valid in classical, modal, deontic, epistemic, intuitionistic, temporal, probabilistic
|
|
91
|
+
const validProfiles = [
|
|
92
|
+
'classical.propositional',
|
|
93
|
+
'classical.first_order',
|
|
94
|
+
'modal.k',
|
|
95
|
+
'deontic.standard',
|
|
96
|
+
'epistemic.s5',
|
|
97
|
+
'intuitionistic.propositional',
|
|
98
|
+
'temporal.ltl',
|
|
99
|
+
'probabilistic.basic',
|
|
100
|
+
];
|
|
101
|
+
for (const profile of validProfiles) {
|
|
102
|
+
(0, vitest_1.it)(`define T := P -> P; check valid T → valid in ${profile}`, () => {
|
|
103
|
+
const out = runOk(`logic ${profile}\ndefine T := P -> P\ncheck valid T`);
|
|
104
|
+
(0, vitest_1.expect)(out.results[0].status).toBe('valid');
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
// Belnap: P -> P is NOT valid (4-valued logic)
|
|
108
|
+
(0, vitest_1.it)('define T := P -> P; check valid T → invalid in paraconsistent.belnap', () => {
|
|
109
|
+
const out = runOk('logic paraconsistent.belnap\ndefine T := P -> P\ncheck valid T');
|
|
110
|
+
(0, vitest_1.expect)(out.results[0].status).toBe('invalid');
|
|
111
|
+
});
|
|
112
|
+
// Arithmetic uses different expressions
|
|
113
|
+
(0, vitest_1.it)('define Sum := 2 + 3; check valid (Sum > 0) in arithmetic', () => {
|
|
114
|
+
const out = runOk('logic arithmetic\ndefine Sum := 2 + 3\ncheck valid (Sum > 0)');
|
|
115
|
+
(0, vitest_1.expect)(out.results[0].status).toBe('valid');
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
// ============================================================
|
|
119
|
+
// 4. define expansion in derive — across profiles
|
|
120
|
+
// ============================================================
|
|
121
|
+
(0, vitest_1.describe)('v3 cross-profile: define expansion in derive', () => {
|
|
122
|
+
const deriveProfiles = [
|
|
123
|
+
'classical.propositional',
|
|
124
|
+
'classical.first_order',
|
|
125
|
+
'modal.k',
|
|
126
|
+
'deontic.standard',
|
|
127
|
+
'epistemic.s5',
|
|
128
|
+
'intuitionistic.propositional',
|
|
129
|
+
'temporal.ltl',
|
|
130
|
+
'probabilistic.basic',
|
|
131
|
+
];
|
|
132
|
+
for (const profile of deriveProfiles) {
|
|
133
|
+
(0, vitest_1.it)(`derive with defined axiom in ${profile}`, () => {
|
|
134
|
+
const out = runOk(`logic ${profile}\n` +
|
|
135
|
+
'define IMP := P -> Q\n' +
|
|
136
|
+
'axiom A1 : IMP\n' +
|
|
137
|
+
'axiom A2 : P\n' +
|
|
138
|
+
'derive Q from {A1, A2}');
|
|
139
|
+
// Some profiles return 'provable', others 'valid'
|
|
140
|
+
(0, vitest_1.expect)(['provable', 'valid']).toContain(out.results[0].status);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
// ============================================================
|
|
145
|
+
// 5. unfold / fold — cross-profile
|
|
146
|
+
// ============================================================
|
|
147
|
+
(0, vitest_1.describe)('v3 cross-profile: unfold + fold', () => {
|
|
148
|
+
for (const profile of PROPOSITIONAL_PROFILES) {
|
|
149
|
+
(0, vitest_1.it)(`unfold D then fold back in ${profile}`, () => {
|
|
150
|
+
const out = runOk(`logic ${profile}\ndefine D := P & Q\nunfold D\nfold (P & Q)`);
|
|
151
|
+
(0, vitest_1.expect)(out.stdout).toContain('Unfold');
|
|
152
|
+
(0, vitest_1.expect)(out.stdout).toContain('Fold');
|
|
153
|
+
// fold should find definition name D
|
|
154
|
+
(0, vitest_1.expect)(out.stdout).toMatch(/Fold:.*D/);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
(0, vitest_1.it)('unfold works in arithmetic', () => {
|
|
158
|
+
const out = runOk('logic arithmetic\ndefine S := 2 + 3\nunfold S');
|
|
159
|
+
(0, vitest_1.expect)(out.stdout).toContain('Unfold');
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
// ============================================================
|
|
163
|
+
// 6. source — cross-profile
|
|
164
|
+
// ============================================================
|
|
165
|
+
(0, vitest_1.describe)('v3 cross-profile: source', () => {
|
|
166
|
+
for (const profile of ALL_PROFILES) {
|
|
167
|
+
(0, vitest_1.it)(`source declaration works in ${profile}`, () => {
|
|
168
|
+
const out = runOk(`logic ${profile}\n` +
|
|
169
|
+
'source Frege {\n' +
|
|
170
|
+
' author "Gottlob Frege"\n' +
|
|
171
|
+
' work "Begriffsschrift"\n' +
|
|
172
|
+
' year 1879\n' +
|
|
173
|
+
'}\n' +
|
|
174
|
+
'glossary');
|
|
175
|
+
(0, vitest_1.expect)(out.stdout).toContain('Frege');
|
|
176
|
+
(0, vitest_1.expect)(out.stdout).toContain('Fuentes');
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
// ============================================================
|
|
181
|
+
// 7. interpret — cross-profile
|
|
182
|
+
// ============================================================
|
|
183
|
+
(0, vitest_1.describe)('v3 cross-profile: interpret', () => {
|
|
184
|
+
for (const profile of PROPOSITIONAL_PROFILES) {
|
|
185
|
+
(0, vitest_1.it)(`interpret creates binding in ${profile}`, () => {
|
|
186
|
+
const out = runOk(`logic ${profile}\n` + 'interpret "premise" as P -> Q\n' + 'glossary');
|
|
187
|
+
(0, vitest_1.expect)(out.stdout).toContain('Interpret');
|
|
188
|
+
(0, vitest_1.expect)(out.stdout).toContain('Interpretaciones');
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
// ============================================================
|
|
193
|
+
// 8. render glossary + analysis — cross-profile
|
|
194
|
+
// ============================================================
|
|
195
|
+
(0, vitest_1.describe)('v3 cross-profile: render glossary', () => {
|
|
196
|
+
const formats = ['markdown', 'json', 'latex'];
|
|
197
|
+
for (const format of formats) {
|
|
198
|
+
(0, vitest_1.it)(`render glossary as ${format} works with propositional`, () => {
|
|
199
|
+
const out = runOk('logic classical.propositional\n' + 'define D := P -> Q\n' + `render glossary as ${format}`);
|
|
200
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
201
|
+
if (format === 'markdown')
|
|
202
|
+
(0, vitest_1.expect)(out.stdout).toContain('**D**');
|
|
203
|
+
if (format === 'json')
|
|
204
|
+
(0, vitest_1.expect)(out.stdout).toContain('"D"');
|
|
205
|
+
if (format === 'latex')
|
|
206
|
+
(0, vitest_1.expect)(out.stdout).toContain('\\newcommand');
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
(0, vitest_1.describe)('v3 cross-profile: render analysis', () => {
|
|
211
|
+
for (const profile of PROPOSITIONAL_PROFILES) {
|
|
212
|
+
(0, vitest_1.it)(`render analysis in ${profile}`, () => {
|
|
213
|
+
const out = runOk(`logic ${profile}\n` +
|
|
214
|
+
'define D := P -> Q\n' +
|
|
215
|
+
'axiom A1 : P -> Q\n' +
|
|
216
|
+
'render analysis as markdown');
|
|
217
|
+
(0, vitest_1.expect)(out.stdout).toContain('Análisis');
|
|
218
|
+
(0, vitest_1.expect)(out.stdout).toContain('Definiciones');
|
|
219
|
+
(0, vitest_1.expect)(out.stdout).toContain('Axiomas');
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
// ============================================================
|
|
224
|
+
// 9. Profile-specific operators inside define
|
|
225
|
+
// ============================================================
|
|
226
|
+
(0, vitest_1.describe)('v3 profile-specific operators in define', () => {
|
|
227
|
+
// Modal: box/diamond
|
|
228
|
+
(0, vitest_1.it)('modal.k: define with []P (necessity)', () => {
|
|
229
|
+
const out = runOk('logic modal.k\ndefine NecP := []P\nunfold NecP');
|
|
230
|
+
(0, vitest_1.expect)(out.stdout).toContain('Unfold');
|
|
231
|
+
});
|
|
232
|
+
(0, vitest_1.it)('modal.k: define with <>P (possibility)', () => {
|
|
233
|
+
const out = runOk('logic modal.k\ndefine PosP := <>P\nunfold PosP');
|
|
234
|
+
(0, vitest_1.expect)(out.stdout).toContain('Unfold');
|
|
235
|
+
});
|
|
236
|
+
// Deontic: O(...), P(...)
|
|
237
|
+
(0, vitest_1.it)('deontic.standard: define with O(P) (obligation)', () => {
|
|
238
|
+
const out = runOk('logic deontic.standard\ndefine Obligatorio := O(P)\nunfold Obligatorio');
|
|
239
|
+
(0, vitest_1.expect)(out.stdout).toContain('Unfold');
|
|
240
|
+
});
|
|
241
|
+
// Epistemic: K(...)
|
|
242
|
+
(0, vitest_1.it)('epistemic.s5: define with K(P) (knowledge)', () => {
|
|
243
|
+
const out = runOk('logic epistemic.s5\ndefine Sabe := K(P)\nunfold Sabe');
|
|
244
|
+
(0, vitest_1.expect)(out.stdout).toContain('Unfold');
|
|
245
|
+
});
|
|
246
|
+
// Epistemic: K(P) -> P is valid in S5
|
|
247
|
+
(0, vitest_1.it)('epistemic.s5: define K(P) -> P is valid (veridicality)', () => {
|
|
248
|
+
const out = runOk('logic epistemic.s5\ndefine Veridical := K(P) -> P\ncheck valid Veridical');
|
|
249
|
+
(0, vitest_1.expect)(out.results[0].status).toBe('valid');
|
|
250
|
+
});
|
|
251
|
+
// Temporal: X(...), U(...)
|
|
252
|
+
(0, vitest_1.it)('temporal.ltl: define with X(P) (next)', () => {
|
|
253
|
+
const out = runOk('logic temporal.ltl\ndefine NextP := X(P)\nunfold NextP');
|
|
254
|
+
(0, vitest_1.expect)(out.stdout).toContain('Unfold');
|
|
255
|
+
});
|
|
256
|
+
// FOL: predicates and quantifiers
|
|
257
|
+
(0, vitest_1.it)('classical.first_order: define with predicate', () => {
|
|
258
|
+
const out = runOk('logic classical.first_order\ndefine Human := P(x) -> Q(x)\nunfold Human');
|
|
259
|
+
(0, vitest_1.expect)(out.stdout).toContain('Unfold');
|
|
260
|
+
});
|
|
261
|
+
(0, vitest_1.it)('classical.first_order: define + check valid (forall tautology)', () => {
|
|
262
|
+
const out = runOk('logic classical.first_order\n' + 'define T := forall x (P(x) -> P(x))\n' + 'check valid T');
|
|
263
|
+
(0, vitest_1.expect)(out.results[0].status).toBe('valid');
|
|
264
|
+
});
|
|
265
|
+
// Arithmetic: numeric operations
|
|
266
|
+
(0, vitest_1.it)('arithmetic: define numeric expression + check valid', () => {
|
|
267
|
+
const out = runOk('logic arithmetic\ndefine Expr := (2 + 3) * 2\ncheck valid (Expr > 5)');
|
|
268
|
+
(0, vitest_1.expect)(out.results[0].status).toBe('valid');
|
|
269
|
+
});
|
|
270
|
+
// Paraconsistent: both values
|
|
271
|
+
(0, vitest_1.it)('paraconsistent.belnap: define + check satisfiable', () => {
|
|
272
|
+
const out = runOk('logic paraconsistent.belnap\ndefine Conj := P & Q\ncheck satisfiable Conj');
|
|
273
|
+
(0, vitest_1.expect)(out.results[0].status).toBe('satisfiable');
|
|
274
|
+
});
|
|
275
|
+
// Intuitionistic: specific behaviors
|
|
276
|
+
(0, vitest_1.it)('intuitionistic: define DNE (double negation elimination) is NOT valid', () => {
|
|
277
|
+
const out = runOk('logic intuitionistic.propositional\ndefine DNE := !!P -> P\ncheck valid DNE');
|
|
278
|
+
// DNE is NOT valid in intuitionistic logic
|
|
279
|
+
(0, vitest_1.expect)(out.results[0].status).toBe('invalid');
|
|
280
|
+
});
|
|
281
|
+
(0, vitest_1.it)('intuitionistic: define (P -> P) IS valid', () => {
|
|
282
|
+
const out = runOk('logic intuitionistic.propositional\ndefine Id := P -> P\ncheck valid Id');
|
|
283
|
+
(0, vitest_1.expect)(out.results[0].status).toBe('valid');
|
|
284
|
+
});
|
|
285
|
+
// Aristotelian: syllogistic only supports its own formula types
|
|
286
|
+
(0, vitest_1.it)('aristotelian.syllogistic: define + glossary', () => {
|
|
287
|
+
const out = runOk('logic aristotelian.syllogistic\n' +
|
|
288
|
+
'define Regla := P -> Q\n' +
|
|
289
|
+
'description "Una regla"\n' +
|
|
290
|
+
'glossary');
|
|
291
|
+
(0, vitest_1.expect)(out.stdout).toContain('GLOSARIO');
|
|
292
|
+
(0, vitest_1.expect)(out.stdout).toContain('Regla');
|
|
293
|
+
});
|
|
294
|
+
// Probabilistic
|
|
295
|
+
(0, vitest_1.it)('probabilistic.basic: define + check valid', () => {
|
|
296
|
+
const out = runOk('logic probabilistic.basic\ndefine Id := P -> P\ncheck valid Id');
|
|
297
|
+
(0, vitest_1.expect)(out.results[0].status).toBe('valid');
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
// ============================================================
|
|
301
|
+
// 10. Combination stress: define + source + interpret + all
|
|
302
|
+
// ============================================================
|
|
303
|
+
(0, vitest_1.describe)('v3 full workflow stress — per profile', () => {
|
|
304
|
+
for (const profile of PROPOSITIONAL_PROFILES) {
|
|
305
|
+
(0, vitest_1.it)(`full workflow (define+source+interpret+unfold+fold+glossary+render) in ${profile}`, () => {
|
|
306
|
+
const out = runOk(`logic ${profile}\n` +
|
|
307
|
+
'source Author {\n' +
|
|
308
|
+
' author "Test Author"\n' +
|
|
309
|
+
' work "Test Work"\n' +
|
|
310
|
+
' year 2025\n' +
|
|
311
|
+
'}\n' +
|
|
312
|
+
'define D := P -> Q\n' +
|
|
313
|
+
'description "Test definition"\n' +
|
|
314
|
+
'interpret "premise" as P -> Q\n' +
|
|
315
|
+
'unfold D\n' +
|
|
316
|
+
'fold (P -> Q)\n' +
|
|
317
|
+
'glossary\n' +
|
|
318
|
+
'render glossary as markdown\n' +
|
|
319
|
+
'render analysis as markdown');
|
|
320
|
+
(0, vitest_1.expect)(out.stdout).toContain('Source');
|
|
321
|
+
(0, vitest_1.expect)(out.stdout).toContain('Define');
|
|
322
|
+
(0, vitest_1.expect)(out.stdout).toContain('Interpret');
|
|
323
|
+
(0, vitest_1.expect)(out.stdout).toContain('Unfold');
|
|
324
|
+
(0, vitest_1.expect)(out.stdout).toContain('Fold');
|
|
325
|
+
(0, vitest_1.expect)(out.stdout).toContain('GLOSARIO');
|
|
326
|
+
(0, vitest_1.expect)(out.stdout).toContain('**D**');
|
|
327
|
+
(0, vitest_1.expect)(out.stdout).toContain('Análisis');
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
// ============================================================
|
|
332
|
+
// 11. Syntactic stress — edge cases, malformed input, limits
|
|
333
|
+
// ============================================================
|
|
334
|
+
(0, vitest_1.describe)('v3 syntactic stress', () => {
|
|
335
|
+
// Many definitions at once
|
|
336
|
+
(0, vitest_1.it)('50 chained definitions without error', () => {
|
|
337
|
+
const defs = Array.from({ length: 50 }, (_, i) => `define D${i} := ${i > 0 ? `D${i - 1} -> P${i}` : 'P0'}`).join('\n');
|
|
338
|
+
const out = runOk(`logic classical.propositional\n${defs}\nglossary`);
|
|
339
|
+
(0, vitest_1.expect)(out.stdout).toContain('D49');
|
|
340
|
+
(0, vitest_1.expect)(out.stdout).toContain('GLOSARIO');
|
|
341
|
+
});
|
|
342
|
+
// Many sources
|
|
343
|
+
(0, vitest_1.it)('20 source declarations without error', () => {
|
|
344
|
+
const sources = Array.from({ length: 20 }, (_, i) => `source S${i} {\n author "Author${i}"\n work "Work${i}"\n year ${1900 + i}\n}`).join('\n');
|
|
345
|
+
const out = runOk(`logic classical.propositional\n${sources}\nglossary`);
|
|
346
|
+
(0, vitest_1.expect)(out.stdout).toContain('S19');
|
|
347
|
+
(0, vitest_1.expect)(out.stdout).toContain('Fuentes');
|
|
348
|
+
});
|
|
349
|
+
// Many interpretations
|
|
350
|
+
(0, vitest_1.it)('20 interpret commands without error', () => {
|
|
351
|
+
const interps = Array.from({ length: 20 }, (_, i) => `interpret "text${i}" as P${i}`).join('\n');
|
|
352
|
+
const out = runOk(`logic classical.propositional\n${interps}\nglossary`);
|
|
353
|
+
(0, vitest_1.expect)(out.stdout).toContain('Interpretaciones');
|
|
354
|
+
(0, vitest_1.expect)(out.stdout).toContain('text19');
|
|
355
|
+
});
|
|
356
|
+
// Deeply nested definition body
|
|
357
|
+
(0, vitest_1.it)('define with deeply nested formula (10 levels of implication)', () => {
|
|
358
|
+
// P -> (P -> (P -> ... ))
|
|
359
|
+
let formula = 'P';
|
|
360
|
+
for (let i = 0; i < 10; i++)
|
|
361
|
+
formula = `(${formula} -> P)`;
|
|
362
|
+
const out = runOk(`logic classical.propositional\ndefine Deep := ${formula}`);
|
|
363
|
+
(0, vitest_1.expect)(out.stdout).toContain('Define');
|
|
364
|
+
(0, vitest_1.expect)(out.stdout).toContain('Deep');
|
|
365
|
+
});
|
|
366
|
+
// Parametric define with many params
|
|
367
|
+
(0, vitest_1.it)('define with 5 params', () => {
|
|
368
|
+
const out = runOk('logic classical.propositional\ndefine F(a, b, c, d, e) := a -> b -> c -> d -> e');
|
|
369
|
+
(0, vitest_1.expect)(out.stdout).toContain('F(a, b, c, d, e)');
|
|
370
|
+
});
|
|
371
|
+
// Empty source block
|
|
372
|
+
(0, vitest_1.it)('source with no fields parses OK', () => {
|
|
373
|
+
const out = runOk('logic classical.propositional\nsource Empty {\n}\nglossary');
|
|
374
|
+
(0, vitest_1.expect)(out.stdout).toContain('Fuentes');
|
|
375
|
+
});
|
|
376
|
+
// Source redefinition warning
|
|
377
|
+
(0, vitest_1.it)('source redefinition produces warning', () => {
|
|
378
|
+
const out = runOk('logic classical.propositional\n' +
|
|
379
|
+
'source S1 {\n author "A"\n}\n' +
|
|
380
|
+
'source S1 {\n author "B"\n}\n' +
|
|
381
|
+
'glossary');
|
|
382
|
+
// Should succeed but with a warning diagnostic
|
|
383
|
+
const warnings = out.diagnostics.filter((d) => d.severity === 'warning');
|
|
384
|
+
(0, vitest_1.expect)(warnings.length).toBeGreaterThan(0);
|
|
385
|
+
});
|
|
386
|
+
// Define overwrite
|
|
387
|
+
(0, vitest_1.it)('redefining same name replaces the definition', () => {
|
|
388
|
+
const out = runOk('logic classical.propositional\ndefine D := P\ndefine D := Q\nglossary');
|
|
389
|
+
// Glossary should show Q, not P
|
|
390
|
+
(0, vitest_1.expect)(out.stdout).toContain('Q');
|
|
391
|
+
});
|
|
392
|
+
// Circular: direct
|
|
393
|
+
(0, vitest_1.it)('circular define (direct) is rejected', () => {
|
|
394
|
+
const out = run('logic classical.propositional\ndefine Loop := Loop');
|
|
395
|
+
(0, vitest_1.expect)(out.exitCode).not.toBe(0);
|
|
396
|
+
});
|
|
397
|
+
// Circular: indirect depth 2
|
|
398
|
+
(0, vitest_1.it)('circular define (indirect depth 2) is rejected', () => {
|
|
399
|
+
const out = run('logic classical.propositional\ndefine A := B\ndefine B := A');
|
|
400
|
+
(0, vitest_1.expect)(out.exitCode).not.toBe(0);
|
|
401
|
+
});
|
|
402
|
+
// Circular: indirect depth 3
|
|
403
|
+
(0, vitest_1.it)('circular define (indirect depth 3) is rejected', () => {
|
|
404
|
+
const out = run('logic classical.propositional\ndefine A := B\ndefine B := C\ndefine C := A');
|
|
405
|
+
(0, vitest_1.expect)(out.exitCode).not.toBe(0);
|
|
406
|
+
});
|
|
407
|
+
// Unfold on undefined name
|
|
408
|
+
(0, vitest_1.it)('unfold on undefined name does not crash', () => {
|
|
409
|
+
const out = runOk('logic classical.propositional\nunfold Unknown');
|
|
410
|
+
(0, vitest_1.expect)(out.stdout).toContain('Unfold');
|
|
411
|
+
});
|
|
412
|
+
// Fold on formula matching no definition
|
|
413
|
+
(0, vitest_1.it)('fold on non-matching formula returns as-is', () => {
|
|
414
|
+
const out = runOk('logic classical.propositional\nfold (P -> Q)');
|
|
415
|
+
(0, vitest_1.expect)(out.results[0].status).toBe('valid');
|
|
416
|
+
});
|
|
417
|
+
// Define inside theory block
|
|
418
|
+
(0, vitest_1.it)('define inside theory block works', () => {
|
|
419
|
+
const out = runOk('logic classical.propositional\n' +
|
|
420
|
+
'theory T {\n' +
|
|
421
|
+
' define D := P -> Q\n' +
|
|
422
|
+
' axiom A1 : D\n' +
|
|
423
|
+
'}');
|
|
424
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
425
|
+
});
|
|
426
|
+
// Multiple theory blocks with their own defines
|
|
427
|
+
(0, vitest_1.it)('separate theory blocks each have own defines', () => {
|
|
428
|
+
const out = runOk('logic classical.propositional\n' +
|
|
429
|
+
'theory T1 {\n' +
|
|
430
|
+
' define D := P\n' +
|
|
431
|
+
' axiom A1 : D\n' +
|
|
432
|
+
'}\n' +
|
|
433
|
+
'theory T2 {\n' +
|
|
434
|
+
' define D := Q\n' +
|
|
435
|
+
' axiom A1 : D\n' +
|
|
436
|
+
'}');
|
|
437
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
438
|
+
});
|
|
439
|
+
// Spanish aliases mixed with English
|
|
440
|
+
(0, vitest_1.it)('mix of Spanish and English keywords', () => {
|
|
441
|
+
const out = runOk('logic classical.propositional\n' +
|
|
442
|
+
'definir D := P -> Q\n' +
|
|
443
|
+
'description "desc"\n' +
|
|
444
|
+
'fuente S {\n' +
|
|
445
|
+
' author "Autor"\n' +
|
|
446
|
+
' work "Obra"\n' +
|
|
447
|
+
'}\n' +
|
|
448
|
+
'interpretar "texto" as P\n' +
|
|
449
|
+
'desplegar D\n' +
|
|
450
|
+
'plegar (P -> Q)\n' +
|
|
451
|
+
'glosario');
|
|
452
|
+
(0, vitest_1.expect)(out.stdout).toContain('Define');
|
|
453
|
+
(0, vitest_1.expect)(out.stdout).toContain('Source');
|
|
454
|
+
(0, vitest_1.expect)(out.stdout).toContain('Interpret');
|
|
455
|
+
(0, vitest_1.expect)(out.stdout).toContain('Unfold');
|
|
456
|
+
(0, vitest_1.expect)(out.stdout).toContain('Fold');
|
|
457
|
+
(0, vitest_1.expect)(out.stdout).toContain('GLOSARIO');
|
|
458
|
+
});
|
|
459
|
+
// Long definition name
|
|
460
|
+
(0, vitest_1.it)('define with very long name (50 chars)', () => {
|
|
461
|
+
const name = 'A'.repeat(50);
|
|
462
|
+
const out = runOk(`logic classical.propositional\ndefine ${name} := P -> Q`);
|
|
463
|
+
(0, vitest_1.expect)(out.stdout).toContain(name);
|
|
464
|
+
});
|
|
465
|
+
// Source with all fields
|
|
466
|
+
(0, vitest_1.it)('source with all 6 fields', () => {
|
|
467
|
+
const out = runOk('logic classical.propositional\n' +
|
|
468
|
+
'source Full {\n' +
|
|
469
|
+
' author "Author"\n' +
|
|
470
|
+
' work "Work"\n' +
|
|
471
|
+
' year 2025\n' +
|
|
472
|
+
' section "Ch.1"\n' +
|
|
473
|
+
' edition "2nd"\n' +
|
|
474
|
+
' url "https://example.com"\n' +
|
|
475
|
+
'}\n' +
|
|
476
|
+
'glossary');
|
|
477
|
+
(0, vitest_1.expect)(out.stdout).toContain('Author');
|
|
478
|
+
(0, vitest_1.expect)(out.stdout).toContain('Fuentes');
|
|
479
|
+
});
|
|
480
|
+
// Negative year in source
|
|
481
|
+
(0, vitest_1.it)('source with negative year', () => {
|
|
482
|
+
const out = runOk('logic classical.propositional\n' +
|
|
483
|
+
'source Ancient {\n' +
|
|
484
|
+
' author "Parmenides"\n' +
|
|
485
|
+
' year -500\n' +
|
|
486
|
+
'}');
|
|
487
|
+
(0, vitest_1.expect)(out.stdout).toContain('Parmenides');
|
|
488
|
+
});
|
|
489
|
+
// interpret with passageRef identifier
|
|
490
|
+
(0, vitest_1.it)('interpret with identifier ref', () => {
|
|
491
|
+
const out = runOk('logic classical.propositional\ninterpret MyRef as P -> Q');
|
|
492
|
+
(0, vitest_1.expect)(out.stdout).toContain('Interpret');
|
|
493
|
+
(0, vitest_1.expect)(out.stdout).toContain('MyRef');
|
|
494
|
+
});
|
|
495
|
+
// Glossary with no entries
|
|
496
|
+
(0, vitest_1.it)('empty glossary is safe', () => {
|
|
497
|
+
const out = runOk('logic classical.propositional\nglossary');
|
|
498
|
+
(0, vitest_1.expect)(out.stdout).toContain('sin definiciones registradas');
|
|
499
|
+
});
|
|
500
|
+
// render glossary with no definitions
|
|
501
|
+
(0, vitest_1.it)('render glossary with no definitions emits placeholder', () => {
|
|
502
|
+
const out = runOk('logic classical.propositional\nrender glossary as markdown');
|
|
503
|
+
(0, vitest_1.expect)(out.stdout).toContain('sin definiciones');
|
|
504
|
+
});
|
|
505
|
+
// render analysis with empty theory
|
|
506
|
+
(0, vitest_1.it)('render analysis with no content is minimal', () => {
|
|
507
|
+
const out = runOk('logic classical.propositional\nrender analysis as markdown');
|
|
508
|
+
(0, vitest_1.expect)(out.stdout).toContain('Análisis');
|
|
509
|
+
});
|
|
510
|
+
// Export define
|
|
511
|
+
(0, vitest_1.it)('export define works', () => {
|
|
512
|
+
const out = runOk('logic classical.propositional\nexport define D := P -> Q');
|
|
513
|
+
(0, vitest_1.expect)(out.stdout).toContain('Define');
|
|
514
|
+
});
|
|
515
|
+
});
|
|
516
|
+
// ============================================================
|
|
517
|
+
// 12. Define interaction with other v2 features
|
|
518
|
+
// ============================================================
|
|
519
|
+
(0, vitest_1.describe)('v3 + v2 feature interactions', () => {
|
|
520
|
+
// define + let binding
|
|
521
|
+
(0, vitest_1.it)('define + let coexist', () => {
|
|
522
|
+
const out = runOk('logic classical.propositional\n' +
|
|
523
|
+
'define D := P -> Q\n' +
|
|
524
|
+
'let x = P & Q\n' +
|
|
525
|
+
'check valid (D | x | !(D | x))');
|
|
526
|
+
(0, vitest_1.expect)(out.results[0].status).toBe('valid');
|
|
527
|
+
});
|
|
528
|
+
// define + truth_table
|
|
529
|
+
(0, vitest_1.it)('define expansion in truth_table', () => {
|
|
530
|
+
const out = runOk('logic classical.propositional\ndefine D := P | !P\ntruth_table D');
|
|
531
|
+
(0, vitest_1.expect)(out.stdout).toContain('T');
|
|
532
|
+
});
|
|
533
|
+
// define + countermodel
|
|
534
|
+
(0, vitest_1.it)('define expansion in countermodel', () => {
|
|
535
|
+
const out = runOk('logic classical.propositional\ndefine D := P\ncountermodel D');
|
|
536
|
+
(0, vitest_1.expect)(out.results[0].status).toBe('invalid');
|
|
537
|
+
});
|
|
538
|
+
// define + check equivalent
|
|
539
|
+
(0, vitest_1.it)('define + check equivalent', () => {
|
|
540
|
+
const out = runOk('logic classical.propositional\n' +
|
|
541
|
+
'define A := P -> Q\n' +
|
|
542
|
+
'define B := !P | Q\n' +
|
|
543
|
+
'check equivalent A, B');
|
|
544
|
+
(0, vitest_1.expect)(out.results[0].status).toBe('valid');
|
|
545
|
+
});
|
|
546
|
+
// define + prove
|
|
547
|
+
(0, vitest_1.it)('define + prove', () => {
|
|
548
|
+
const out = runOk('logic classical.propositional\n' +
|
|
549
|
+
'define IMP := P -> Q\n' +
|
|
550
|
+
'axiom A1 : IMP\n' +
|
|
551
|
+
'axiom A2 : P\n' +
|
|
552
|
+
'prove Q from {A1, A2}');
|
|
553
|
+
(0, vitest_1.expect)(out.results[0].status).toBe('provable');
|
|
554
|
+
});
|
|
555
|
+
// define + analyze (analyze works with raw formulas)
|
|
556
|
+
(0, vitest_1.it)('define + analyze', () => {
|
|
557
|
+
const out = runOk('logic classical.propositional\n' + 'define IMP := P -> Q\n' + 'analyze {(P -> Q), P} -> Q');
|
|
558
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
559
|
+
});
|
|
560
|
+
// define + explain
|
|
561
|
+
(0, vitest_1.it)('define + explain', () => {
|
|
562
|
+
const out = runOk('logic classical.propositional\ndefine T := P -> P\nexplain (P -> P)');
|
|
563
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
564
|
+
});
|
|
565
|
+
// define + truth_table (v2 feature)
|
|
566
|
+
(0, vitest_1.it)('define + check satisfiable', () => {
|
|
567
|
+
const out = runOk('logic classical.propositional\ndefine D := P & Q\ncheck satisfiable D');
|
|
568
|
+
(0, vitest_1.expect)(out.results[0].status).toBe('satisfiable');
|
|
569
|
+
});
|
|
570
|
+
// define in if/else block
|
|
571
|
+
(0, vitest_1.it)('define before if/else block works', () => {
|
|
572
|
+
const out = runOk('logic classical.propositional\n' +
|
|
573
|
+
'define T := P -> P\n' +
|
|
574
|
+
'if valid (P | !P) {\n' +
|
|
575
|
+
' check valid T\n' +
|
|
576
|
+
'}');
|
|
577
|
+
(0, vitest_1.expect)(out.results[0].status).toBe('valid');
|
|
578
|
+
});
|
|
579
|
+
// define with check inside if
|
|
580
|
+
(0, vitest_1.it)('define + if valid with defined tautology', () => {
|
|
581
|
+
const out = runOk('logic classical.propositional\n' +
|
|
582
|
+
'define LEM := P | !P\n' +
|
|
583
|
+
'if valid (P | !P) {\n' +
|
|
584
|
+
' print "LEM holds"\n' +
|
|
585
|
+
'}');
|
|
586
|
+
(0, vitest_1.expect)(out.stdout).toContain('LEM holds');
|
|
587
|
+
});
|
|
588
|
+
// source + claim
|
|
589
|
+
(0, vitest_1.it)('source + claim integration', () => {
|
|
590
|
+
const out = runOk('logic classical.propositional\n' +
|
|
591
|
+
'source S {\n' +
|
|
592
|
+
' author "Author"\n' +
|
|
593
|
+
' work "Work"\n' +
|
|
594
|
+
'}\n' +
|
|
595
|
+
'let p = passage([[ref#1]])\n' +
|
|
596
|
+
'let phi = formalize p as (P -> Q)\n' +
|
|
597
|
+
'claim C = phi\n' +
|
|
598
|
+
'render analysis as markdown');
|
|
599
|
+
(0, vitest_1.expect)(out.stdout).toContain('Fuentes');
|
|
600
|
+
(0, vitest_1.expect)(out.stdout).toContain('Análisis');
|
|
601
|
+
});
|
|
602
|
+
// define + passage + formalize
|
|
603
|
+
(0, vitest_1.it)('define + passage coexistence', () => {
|
|
604
|
+
const out = runOk('logic classical.propositional\n' +
|
|
605
|
+
'define D := P -> Q\n' +
|
|
606
|
+
'let p1 = passage([[ref#1]])\n' +
|
|
607
|
+
'let phi = formalize p1 as (P -> Q)\n' +
|
|
608
|
+
'glossary');
|
|
609
|
+
(0, vitest_1.expect)(out.stdout).toContain('GLOSARIO');
|
|
610
|
+
});
|
|
611
|
+
});
|
|
612
|
+
// ============================================================
|
|
613
|
+
// 13. Heavy stress: many ops, large scripts
|
|
614
|
+
// ============================================================
|
|
615
|
+
(0, vitest_1.describe)('v3 heavy stress', () => {
|
|
616
|
+
(0, vitest_1.it)('100 defines + check valid on the last one', () => {
|
|
617
|
+
const defs = Array.from({ length: 100 }, (_, i) => `define D${i} := P${i} -> P${i}`).join('\n');
|
|
618
|
+
const out = runOk(`logic classical.propositional\n${defs}\ncheck valid D99`);
|
|
619
|
+
(0, vitest_1.expect)(out.results[0].status).toBe('valid');
|
|
620
|
+
});
|
|
621
|
+
(0, vitest_1.it)('50 defines + 50 unfolds', () => {
|
|
622
|
+
const lines = [];
|
|
623
|
+
for (let i = 0; i < 50; i++) {
|
|
624
|
+
lines.push(`define D${i} := P${i} -> Q${i}`);
|
|
625
|
+
}
|
|
626
|
+
for (let i = 0; i < 50; i++) {
|
|
627
|
+
lines.push(`unfold D${i}`);
|
|
628
|
+
}
|
|
629
|
+
const out = runOk(`logic classical.propositional\n${lines.join('\n')}`);
|
|
630
|
+
(0, vitest_1.expect)(out.results).toHaveLength(50);
|
|
631
|
+
});
|
|
632
|
+
(0, vitest_1.it)('define chain depth 30 + unfold last', () => {
|
|
633
|
+
const defs = ['define D0 := P'];
|
|
634
|
+
for (let i = 1; i < 30; i++) {
|
|
635
|
+
defs.push(`define D${i} := D${i - 1} -> Q${i}`);
|
|
636
|
+
}
|
|
637
|
+
defs.push('unfold D29');
|
|
638
|
+
const out = runOk(`logic classical.propositional\n${defs.join('\n')}`);
|
|
639
|
+
(0, vitest_1.expect)(out.stdout).toContain('Unfold');
|
|
640
|
+
});
|
|
641
|
+
(0, vitest_1.it)('10 sources + 10 defines + 10 interprets + glossary', () => {
|
|
642
|
+
const lines = [];
|
|
643
|
+
for (let i = 0; i < 10; i++) {
|
|
644
|
+
lines.push(`source S${i} {\n author "A${i}"\n work "W${i}"\n year ${2000 + i}\n}`);
|
|
645
|
+
}
|
|
646
|
+
for (let i = 0; i < 10; i++) {
|
|
647
|
+
lines.push(`define D${i} := P${i} -> Q${i}\ndescription "Desc ${i}"`);
|
|
648
|
+
}
|
|
649
|
+
for (let i = 0; i < 10; i++) {
|
|
650
|
+
lines.push(`interpret "text ${i}" as P${i}`);
|
|
651
|
+
}
|
|
652
|
+
lines.push('glossary');
|
|
653
|
+
const out = runOk(`logic classical.propositional\n${lines.join('\n')}`);
|
|
654
|
+
(0, vitest_1.expect)(out.stdout).toContain('GLOSARIO');
|
|
655
|
+
(0, vitest_1.expect)(out.stdout).toContain('Fuentes');
|
|
656
|
+
(0, vitest_1.expect)(out.stdout).toContain('Interpretaciones');
|
|
657
|
+
(0, vitest_1.expect)(out.stdout).toContain('D9');
|
|
658
|
+
(0, vitest_1.expect)(out.stdout).toContain('S9');
|
|
659
|
+
(0, vitest_1.expect)(out.stdout).toContain('text 9');
|
|
660
|
+
});
|
|
661
|
+
(0, vitest_1.it)('render analysis with all v3 features combined', () => {
|
|
662
|
+
const out = runOk('logic classical.propositional\n' +
|
|
663
|
+
'source Frege {\n author "Frege"\n work "Begriffsschrift"\n year 1879\n}\n' +
|
|
664
|
+
'define Impl(x, y) := x -> y\n' +
|
|
665
|
+
'description "Implicación material"\n' +
|
|
666
|
+
'define LEM := P | !P\n' +
|
|
667
|
+
'description "Ley del tercero excluido"\n' +
|
|
668
|
+
'axiom A1 : P -> Q\n' +
|
|
669
|
+
'axiom A2 : P\n' +
|
|
670
|
+
'theorem T1 = Q\n' +
|
|
671
|
+
'interpret "si P entonces Q" as P -> Q\n' +
|
|
672
|
+
'check valid LEM\n' +
|
|
673
|
+
'check valid Impl(P, P)\n' +
|
|
674
|
+
'derive Q from {A1, A2}\n' +
|
|
675
|
+
'glossary\n' +
|
|
676
|
+
'render glossary as json\n' +
|
|
677
|
+
'render analysis as markdown');
|
|
678
|
+
(0, vitest_1.expect)(out.stdout).toContain('Análisis');
|
|
679
|
+
(0, vitest_1.expect)(out.stdout).toContain('Definiciones');
|
|
680
|
+
(0, vitest_1.expect)(out.stdout).toContain('Axiomas');
|
|
681
|
+
(0, vitest_1.expect)(out.stdout).toContain('Fuentes');
|
|
682
|
+
(0, vitest_1.expect)(out.stdout).toContain('Verificaciones');
|
|
683
|
+
(0, vitest_1.expect)(out.results.length).toBeGreaterThanOrEqual(3);
|
|
684
|
+
});
|
|
685
|
+
// Parametric define with all propositional profiles
|
|
686
|
+
(0, vitest_1.it)('parametric define Impl(x,y) := x -> y + check valid Impl(A,A) across all propositional profiles', () => {
|
|
687
|
+
const validProfiles = [
|
|
688
|
+
'classical.propositional',
|
|
689
|
+
'classical.first_order',
|
|
690
|
+
'modal.k',
|
|
691
|
+
'deontic.standard',
|
|
692
|
+
'epistemic.s5',
|
|
693
|
+
'intuitionistic.propositional',
|
|
694
|
+
'temporal.ltl',
|
|
695
|
+
'probabilistic.basic',
|
|
696
|
+
];
|
|
697
|
+
for (const profile of validProfiles) {
|
|
698
|
+
const out = runOk(`logic ${profile}\n` + 'define Impl(x, y) := x -> y\n' + 'check valid Impl(A, A)');
|
|
699
|
+
(0, vitest_1.expect)(out.results[0].status).toBe('valid');
|
|
700
|
+
}
|
|
701
|
+
});
|
|
702
|
+
});
|
|
703
|
+
// ============================================================
|
|
704
|
+
// 14. Regression guards
|
|
705
|
+
// ============================================================
|
|
706
|
+
(0, vitest_1.describe)('v3 regression guards', () => {
|
|
707
|
+
// Ensure define doesn't break normal axiom/theorem workflow
|
|
708
|
+
(0, vitest_1.it)('normal axiom+theorem workflow unaffected by define presence', () => {
|
|
709
|
+
const out = runOk('logic classical.propositional\n' +
|
|
710
|
+
'define D := P -> Q\n' +
|
|
711
|
+
'axiom A1 : P -> Q\n' +
|
|
712
|
+
'axiom A2 : Q -> R\n' +
|
|
713
|
+
'theorem T1 = P -> R\n' +
|
|
714
|
+
'derive R from {A1, A2, T1}');
|
|
715
|
+
// Should be provable as before
|
|
716
|
+
(0, vitest_1.expect)(out.results.length).toBeGreaterThan(0);
|
|
717
|
+
});
|
|
718
|
+
// Ensure source doesn't interfere with text layer
|
|
719
|
+
(0, vitest_1.it)('source + passage + claim coexist without errors', () => {
|
|
720
|
+
const out = runOk('logic classical.propositional\n' +
|
|
721
|
+
'source S {\n author "A"\n work "W"\n}\n' +
|
|
722
|
+
'let p1 = passage([[ref#1]])\n' +
|
|
723
|
+
'let phi = formalize p1 as P\n' +
|
|
724
|
+
'claim C = phi\n' +
|
|
725
|
+
'render analysis as markdown');
|
|
726
|
+
(0, vitest_1.expect)(out.exitCode).toBe(0);
|
|
727
|
+
});
|
|
728
|
+
// Ensure glossary after complex theory
|
|
729
|
+
(0, vitest_1.it)('glossary after theory with extends', () => {
|
|
730
|
+
const out = runOk('logic classical.propositional\n' +
|
|
731
|
+
'theory Base {\n' +
|
|
732
|
+
' axiom A1 : P -> Q\n' +
|
|
733
|
+
'}\n' +
|
|
734
|
+
'theory Ext extends Base {\n' +
|
|
735
|
+
' axiom A2 : Q -> R\n' +
|
|
736
|
+
'}\n' +
|
|
737
|
+
'define D := P -> R\n' +
|
|
738
|
+
'glossary');
|
|
739
|
+
(0, vitest_1.expect)(out.stdout).toContain('GLOSARIO');
|
|
740
|
+
(0, vitest_1.expect)(out.stdout).toContain('D');
|
|
741
|
+
});
|
|
742
|
+
// for loop with define
|
|
743
|
+
(0, vitest_1.it)('define before for loop', () => {
|
|
744
|
+
const out = runOk('logic classical.propositional\n' +
|
|
745
|
+
'define T := P -> P\n' +
|
|
746
|
+
'for F in {P, Q, R} {\n' +
|
|
747
|
+
' check valid (F -> F)\n' +
|
|
748
|
+
'}\n' +
|
|
749
|
+
'check valid T');
|
|
750
|
+
// 3 checks from loop + 1 final check = 4 results
|
|
751
|
+
(0, vitest_1.expect)(out.results.length).toBe(4);
|
|
752
|
+
(0, vitest_1.expect)(out.results[3].status).toBe('valid');
|
|
753
|
+
});
|
|
754
|
+
});
|
|
755
|
+
//# sourceMappingURL=v3-stress.test.js.map
|