@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
|
@@ -54,6 +54,10 @@ export declare class Interpreter {
|
|
|
54
54
|
/** Memoización automática para funciones con argumentos numéricos (fibonacci, factorial, etc.) */
|
|
55
55
|
private fnMemoCache;
|
|
56
56
|
private static readonly MEMO_CACHE_MAX;
|
|
57
|
+
/** v3: Formal definitions (define Name(params?) := body) */
|
|
58
|
+
private definitions;
|
|
59
|
+
/** v3: Bibliographic sources */
|
|
60
|
+
private sources;
|
|
57
61
|
constructor();
|
|
58
62
|
/** Registra funciones nativas (Built-ins) para metaprogramación e interactividad */
|
|
59
63
|
private registerBuiltins;
|
|
@@ -115,6 +119,10 @@ export declare class Interpreter {
|
|
|
115
119
|
private execConfidenceDecl;
|
|
116
120
|
private execContextDecl;
|
|
117
121
|
private execRenderCmd;
|
|
122
|
+
/** Render glossary in the specified format */
|
|
123
|
+
private renderGlossary;
|
|
124
|
+
/** Render full analysis document */
|
|
125
|
+
private renderAnalysis;
|
|
118
126
|
private execAnalyzeCmd;
|
|
119
127
|
private execProofBlock;
|
|
120
128
|
private execTheoryDecl;
|
|
@@ -126,6 +134,22 @@ export declare class Interpreter {
|
|
|
126
134
|
private execWhileStmt;
|
|
127
135
|
private execFnDecl;
|
|
128
136
|
private execReturnStmt;
|
|
137
|
+
private execDefineDecl;
|
|
138
|
+
/** Detect circular definitions (A := ... A ...) */
|
|
139
|
+
private checkCircularDefinition;
|
|
140
|
+
/** Expand a definition by name with given arguments */
|
|
141
|
+
private expandDefinition;
|
|
142
|
+
/** Recursively substitute parameter names with actual argument formulas */
|
|
143
|
+
private substituteParams;
|
|
144
|
+
/** Expand all definitions in a formula (one level) */
|
|
145
|
+
private expandDefinitionsInFormula;
|
|
146
|
+
/** Try to fold a formula back into a definition reference */
|
|
147
|
+
private foldFormula;
|
|
148
|
+
private execUnfoldCmd;
|
|
149
|
+
private execFoldCmd;
|
|
150
|
+
private execSourceDecl;
|
|
151
|
+
private execInterpretCmd;
|
|
152
|
+
private execGlossaryCmd;
|
|
129
153
|
private executeFnCall;
|
|
130
154
|
private startFunctionFrame;
|
|
131
155
|
private createFunctionFrame;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interpreter.d.ts","sourceRoot":"","sources":["../../src/runtime/interpreter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,MAAM,EAGN,eAAe,EACf,YAAY,EAGZ,cAAc,EACd,OAAO,
|
|
1
|
+
{"version":3,"file":"interpreter.d.ts","sourceRoot":"","sources":["../../src/runtime/interpreter.ts"],"names":[],"mappings":"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"}
|
|
@@ -56,6 +56,10 @@ class Interpreter {
|
|
|
56
56
|
/** Memoización automática para funciones con argumentos numéricos (fibonacci, factorial, etc.) */
|
|
57
57
|
fnMemoCache = new Map();
|
|
58
58
|
static MEMO_CACHE_MAX = 50000;
|
|
59
|
+
/** v3: Formal definitions (define Name(params?) := body) */
|
|
60
|
+
definitions = new Map();
|
|
61
|
+
/** v3: Bibliographic sources */
|
|
62
|
+
sources = new Map();
|
|
59
63
|
constructor() {
|
|
60
64
|
this.theory = this.createEmptyTheory();
|
|
61
65
|
this.textLayer = (0, compiler_1.createTextLayerState)();
|
|
@@ -120,6 +124,8 @@ class Interpreter {
|
|
|
120
124
|
this.runtimeStepCount = 0;
|
|
121
125
|
this.runtimeCallCount = 0;
|
|
122
126
|
this.fnMemoCache.clear();
|
|
127
|
+
this.definitions.clear();
|
|
128
|
+
this.sources.clear();
|
|
123
129
|
}
|
|
124
130
|
// ── Memoización de funciones ──────────────────────────────
|
|
125
131
|
/** Serializa una fórmula a una cadena para usar como clave de cache */
|
|
@@ -159,6 +165,9 @@ class Interpreter {
|
|
|
159
165
|
case 'import_decl':
|
|
160
166
|
case 'export_decl':
|
|
161
167
|
case 'logic_decl':
|
|
168
|
+
case 'glossary_cmd':
|
|
169
|
+
case 'unfold_cmd':
|
|
170
|
+
case 'fold_cmd':
|
|
162
171
|
return false;
|
|
163
172
|
case 'if_stmt': {
|
|
164
173
|
const ifS = s;
|
|
@@ -449,6 +458,18 @@ class Interpreter {
|
|
|
449
458
|
return;
|
|
450
459
|
case 'export_decl':
|
|
451
460
|
return this.execExportDecl(stmt);
|
|
461
|
+
case 'define_decl':
|
|
462
|
+
return this.execDefineDecl(stmt);
|
|
463
|
+
case 'unfold_cmd':
|
|
464
|
+
return this.execUnfoldCmd(stmt);
|
|
465
|
+
case 'fold_cmd':
|
|
466
|
+
return this.execFoldCmd(stmt);
|
|
467
|
+
case 'source_decl':
|
|
468
|
+
return this.execSourceDecl(stmt);
|
|
469
|
+
case 'interpret_cmd':
|
|
470
|
+
return this.execInterpretCmd(stmt);
|
|
471
|
+
case 'glossary_cmd':
|
|
472
|
+
return this.execGlossaryCmd(stmt);
|
|
452
473
|
}
|
|
453
474
|
}
|
|
454
475
|
executeStatementsIterative(statements, fallbackFile) {
|
|
@@ -617,6 +638,18 @@ class Interpreter {
|
|
|
617
638
|
return;
|
|
618
639
|
case 'export_decl':
|
|
619
640
|
return this.execExportDecl(stmt);
|
|
641
|
+
case 'define_decl':
|
|
642
|
+
return this.execDefineDecl(stmt);
|
|
643
|
+
case 'unfold_cmd':
|
|
644
|
+
return this.execUnfoldCmd(stmt);
|
|
645
|
+
case 'fold_cmd':
|
|
646
|
+
return this.execFoldCmd(stmt);
|
|
647
|
+
case 'source_decl':
|
|
648
|
+
return this.execSourceDecl(stmt);
|
|
649
|
+
case 'interpret_cmd':
|
|
650
|
+
return this.execInterpretCmd(stmt);
|
|
651
|
+
case 'glossary_cmd':
|
|
652
|
+
return this.execGlossaryCmd(stmt);
|
|
620
653
|
}
|
|
621
654
|
}
|
|
622
655
|
selectIfBody(stmt) {
|
|
@@ -734,6 +767,13 @@ class Interpreter {
|
|
|
734
767
|
case 'theory_decl':
|
|
735
768
|
this.exportedTheories.set(s.name, this.theories.get(s.name));
|
|
736
769
|
break;
|
|
770
|
+
case 'define_decl': {
|
|
771
|
+
const defEntry = this.definitions.get(s.name);
|
|
772
|
+
if (defEntry) {
|
|
773
|
+
this.exportedBindings.set(s.name, defEntry.body);
|
|
774
|
+
}
|
|
775
|
+
break;
|
|
776
|
+
}
|
|
737
777
|
}
|
|
738
778
|
}
|
|
739
779
|
requireProfile() {
|
|
@@ -832,6 +872,32 @@ class Interpreter {
|
|
|
832
872
|
visited.delete(f.name);
|
|
833
873
|
return result;
|
|
834
874
|
}
|
|
875
|
+
// v3: Expand definitions (no-param definitions referenced as atoms)
|
|
876
|
+
const def = this.definitions.get(f.name);
|
|
877
|
+
if (def && (!def.params || def.params.length === 0)) {
|
|
878
|
+
if (visited.has(f.name))
|
|
879
|
+
return f;
|
|
880
|
+
visited.add(f.name);
|
|
881
|
+
const result = this.resolveFormulaRecursive(def.body, visited);
|
|
882
|
+
visited.delete(f.name);
|
|
883
|
+
return result;
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
// v3: Expand parametric definitions used as predicates: F(a, b)
|
|
887
|
+
if (f.kind === 'predicate' && f.name) {
|
|
888
|
+
const def = this.definitions.get(f.name);
|
|
889
|
+
if (def && def.params && def.params.length > 0) {
|
|
890
|
+
// Predicates store arguments as params (string[]) or args (Formula[])
|
|
891
|
+
let argFormulas;
|
|
892
|
+
if (f.args && f.args.length > 0) {
|
|
893
|
+
argFormulas = f.args.map((a) => (a ? this.resolveFormulaRecursive(a, visited) : a));
|
|
894
|
+
}
|
|
895
|
+
else {
|
|
896
|
+
argFormulas = (f.params ?? []).map((p) => ({ kind: 'atom', name: p, source: f.source }));
|
|
897
|
+
}
|
|
898
|
+
const expanded = this.substituteParams(def.body, def.params, argFormulas);
|
|
899
|
+
return this.resolveFormulaRecursive(expanded, visited);
|
|
900
|
+
}
|
|
835
901
|
}
|
|
836
902
|
// Llamada a función como expresión
|
|
837
903
|
if (f.kind === 'fn_call' && f.name) {
|
|
@@ -937,6 +1003,9 @@ class Interpreter {
|
|
|
937
1003
|
let isSatisfiable = false;
|
|
938
1004
|
let count = 0;
|
|
939
1005
|
let satCount = 0;
|
|
1006
|
+
// Accumulate rows for graphic view (cap at 512 to avoid OOM on huge tables)
|
|
1007
|
+
const MAX_GRAPHIC_ROWS = 512;
|
|
1008
|
+
const rows = [];
|
|
940
1009
|
for (const v of (0, propositional_1.generateValuationsLazy)(atoms)) {
|
|
941
1010
|
const res = (0, propositional_1.evaluateClassical)(formula, v);
|
|
942
1011
|
if (res) {
|
|
@@ -947,6 +1016,10 @@ class Interpreter {
|
|
|
947
1016
|
isTautology = false;
|
|
948
1017
|
}
|
|
949
1018
|
count++;
|
|
1019
|
+
// Accumulate rows for the graphic table (capped)
|
|
1020
|
+
if (count <= MAX_GRAPHIC_ROWS) {
|
|
1021
|
+
rows.push({ valuation: { ...v }, result: res });
|
|
1022
|
+
}
|
|
950
1023
|
// Solo imprimir las primeras 64 filas para no saturar el stdout en tablas masivas
|
|
951
1024
|
if (count <= 64) {
|
|
952
1025
|
const row = atoms.map((a) => (v[a] ? 'V' : 'F')).join(' | ');
|
|
@@ -963,13 +1036,14 @@ class Interpreter {
|
|
|
963
1036
|
output: `Tabla de verdad de ${count} filas procesada.`,
|
|
964
1037
|
truthTable: {
|
|
965
1038
|
variables: atoms,
|
|
966
|
-
rows
|
|
1039
|
+
rows,
|
|
967
1040
|
subFormulas: [],
|
|
968
1041
|
subFormulaValues: [],
|
|
969
1042
|
isTautology,
|
|
970
1043
|
isContradiction: !isSatisfiable,
|
|
971
1044
|
isSatisfiable,
|
|
972
1045
|
satisfyingCount: satCount,
|
|
1046
|
+
totalCount: count,
|
|
973
1047
|
},
|
|
974
1048
|
diagnostics: [],
|
|
975
1049
|
formula: formula,
|
|
@@ -1070,6 +1144,12 @@ class Interpreter {
|
|
|
1070
1144
|
execRenderCmd(stmt) {
|
|
1071
1145
|
const diags = (0, compiler_1.compileClaimsToTheory)(this.textLayer, this.theory);
|
|
1072
1146
|
this.diagnostics.push(...diags);
|
|
1147
|
+
if (stmt.target === 'glossary') {
|
|
1148
|
+
return this.renderGlossary(stmt.format);
|
|
1149
|
+
}
|
|
1150
|
+
if (stmt.target === 'analysis') {
|
|
1151
|
+
return this.renderAnalysis(stmt.format);
|
|
1152
|
+
}
|
|
1073
1153
|
if (stmt.target === 'claims' || stmt.target === 'all') {
|
|
1074
1154
|
this.emit(`── Render: ${stmt.target} (${stmt.format}) ──`);
|
|
1075
1155
|
for (const [name, claim] of this.theory.claims) {
|
|
@@ -1113,6 +1193,98 @@ class Interpreter {
|
|
|
1113
1193
|
this.emit(`Render: ${stmt.target} (${stmt.format})`);
|
|
1114
1194
|
}
|
|
1115
1195
|
}
|
|
1196
|
+
/** Render glossary in the specified format */
|
|
1197
|
+
renderGlossary(format) {
|
|
1198
|
+
if (format === 'json') {
|
|
1199
|
+
const obj = {};
|
|
1200
|
+
for (const [name, def] of this.definitions) {
|
|
1201
|
+
obj[name] = {
|
|
1202
|
+
params: def.params ?? [],
|
|
1203
|
+
body: (0, propositional_1.formulaToString)(def.body),
|
|
1204
|
+
description: def.description ?? null,
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1207
|
+
this.emit(JSON.stringify(obj, null, 2));
|
|
1208
|
+
return;
|
|
1209
|
+
}
|
|
1210
|
+
// markdown or default
|
|
1211
|
+
if (this.definitions.size === 0) {
|
|
1212
|
+
this.emit('(sin definiciones)');
|
|
1213
|
+
return;
|
|
1214
|
+
}
|
|
1215
|
+
for (const [name, def] of this.definitions) {
|
|
1216
|
+
const paramsStr = def.params?.length ? `(${def.params.join(', ')})` : '';
|
|
1217
|
+
const bodyStr = format === 'latex' ? (0, format_1.formulaToLaTeX)(def.body) : (0, format_1.formulaToUnicode)(def.body);
|
|
1218
|
+
if (format === 'latex') {
|
|
1219
|
+
this.emit(`\\newcommand{\\${name}}{${bodyStr}} % ${def.description ?? ''}`);
|
|
1220
|
+
}
|
|
1221
|
+
else {
|
|
1222
|
+
this.emit(`- **${name}${paramsStr}** := ${bodyStr}`);
|
|
1223
|
+
if (def.description)
|
|
1224
|
+
this.emit(` > ${def.description}`);
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
/** Render full analysis document */
|
|
1229
|
+
renderAnalysis(format) {
|
|
1230
|
+
const isLatex = format === 'latex';
|
|
1231
|
+
const heading = (level, text) => {
|
|
1232
|
+
if (isLatex)
|
|
1233
|
+
return `${'\\'.repeat(1)}${'sub'.repeat(level - 1)}section{${text}}`;
|
|
1234
|
+
return `${'#'.repeat(level)} ${text}`;
|
|
1235
|
+
};
|
|
1236
|
+
this.emit(heading(1, 'Análisis'));
|
|
1237
|
+
this.emit('');
|
|
1238
|
+
// Sources
|
|
1239
|
+
if (this.sources.size > 0) {
|
|
1240
|
+
this.emit(heading(2, 'Fuentes'));
|
|
1241
|
+
for (const [, src] of this.sources) {
|
|
1242
|
+
const yearStr = src.year ? ` (${src.year})` : '';
|
|
1243
|
+
this.emit(`- ${src.author ?? ''}${yearStr} *${src.work ?? ''}*`);
|
|
1244
|
+
}
|
|
1245
|
+
this.emit('');
|
|
1246
|
+
}
|
|
1247
|
+
// Definitions
|
|
1248
|
+
if (this.definitions.size > 0) {
|
|
1249
|
+
this.emit(heading(2, 'Definiciones'));
|
|
1250
|
+
this.renderGlossary(format);
|
|
1251
|
+
this.emit('');
|
|
1252
|
+
}
|
|
1253
|
+
// Axioms
|
|
1254
|
+
if (this.theory.axioms.size > 0) {
|
|
1255
|
+
this.emit(heading(2, 'Axiomas'));
|
|
1256
|
+
for (const [name, formula] of this.theory.axioms) {
|
|
1257
|
+
this.emit(`- **${name}**: ${(0, format_1.formulaToUnicode)(formula)}`);
|
|
1258
|
+
}
|
|
1259
|
+
this.emit('');
|
|
1260
|
+
}
|
|
1261
|
+
// Theorems
|
|
1262
|
+
if (this.theory.theorems.size > 0) {
|
|
1263
|
+
this.emit(heading(2, 'Teoremas'));
|
|
1264
|
+
for (const [name, formula] of this.theory.theorems) {
|
|
1265
|
+
this.emit(`- **${name}**: ${(0, format_1.formulaToUnicode)(formula)}`);
|
|
1266
|
+
}
|
|
1267
|
+
this.emit('');
|
|
1268
|
+
}
|
|
1269
|
+
// Claims
|
|
1270
|
+
if (this.theory.claims.size > 0) {
|
|
1271
|
+
this.emit(heading(2, 'Claims'));
|
|
1272
|
+
for (const [name, claim] of this.theory.claims) {
|
|
1273
|
+
const fStr = claim.formula ? (0, format_1.formulaToUnicode)(claim.formula) : '(sin fórmula)';
|
|
1274
|
+
this.emit(`- **${name}**: ${fStr}`);
|
|
1275
|
+
}
|
|
1276
|
+
this.emit('');
|
|
1277
|
+
}
|
|
1278
|
+
// Results summary
|
|
1279
|
+
if (this.results.length > 0) {
|
|
1280
|
+
this.emit(heading(2, 'Verificaciones'));
|
|
1281
|
+
for (const r of this.results) {
|
|
1282
|
+
const status = r.status === 'valid' ? '✓' : r.status === 'satisfiable' ? '~' : '✗';
|
|
1283
|
+
const fStr = r.formula ? (0, format_1.formulaToUnicode)(r.formula) : '';
|
|
1284
|
+
this.emit(`- ${fStr}: ${r.status} ${status}`);
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1116
1288
|
execAnalyzeCmd(stmt) {
|
|
1117
1289
|
const profile = this.requireProfile();
|
|
1118
1290
|
const premises = stmt.premises.map((p) => this.resolveFormula(p));
|
|
@@ -1341,6 +1513,242 @@ class Interpreter {
|
|
|
1341
1513
|
this.returnValue = undefined;
|
|
1342
1514
|
this.returnSignal = true;
|
|
1343
1515
|
}
|
|
1516
|
+
// ── v3: Definitions, sources, glossary ──────────────────────────
|
|
1517
|
+
execDefineDecl(stmt) {
|
|
1518
|
+
// Check for circular definitions
|
|
1519
|
+
this.checkCircularDefinition(stmt.name, stmt.body, new Set());
|
|
1520
|
+
const entry = {
|
|
1521
|
+
name: stmt.name,
|
|
1522
|
+
params: stmt.params,
|
|
1523
|
+
body: stmt.body,
|
|
1524
|
+
description: stmt.description,
|
|
1525
|
+
};
|
|
1526
|
+
this.definitions.set(stmt.name, entry);
|
|
1527
|
+
const diags = (0, compiler_1.registerDefinition)(this.textLayer, entry);
|
|
1528
|
+
this.diagnostics.push(...diags);
|
|
1529
|
+
this.invalidateResolveCache();
|
|
1530
|
+
const paramsStr = stmt.params?.length ? `(${stmt.params.join(', ')})` : '';
|
|
1531
|
+
const bodyStr = (0, format_1.formulaToUnicode)(stmt.body);
|
|
1532
|
+
this.emit(`Define ${stmt.name}${paramsStr} := ${bodyStr}`);
|
|
1533
|
+
if (stmt.description) {
|
|
1534
|
+
this.emit(` → "${stmt.description}"`);
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
/** Detect circular definitions (A := ... A ...) */
|
|
1538
|
+
checkCircularDefinition(name, body, visited) {
|
|
1539
|
+
if (!body)
|
|
1540
|
+
return;
|
|
1541
|
+
if (body.kind === 'atom' && body.name) {
|
|
1542
|
+
if (body.name === name) {
|
|
1543
|
+
throw new Error(`Definición circular detectada: '${name}' se refiere a sí mismo`);
|
|
1544
|
+
}
|
|
1545
|
+
if (visited.has(body.name))
|
|
1546
|
+
return;
|
|
1547
|
+
visited.add(body.name);
|
|
1548
|
+
const dep = this.definitions.get(body.name);
|
|
1549
|
+
if (dep) {
|
|
1550
|
+
this.checkCircularDefinition(name, dep.body, visited);
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
if (body.args) {
|
|
1554
|
+
for (const arg of body.args) {
|
|
1555
|
+
if (arg)
|
|
1556
|
+
this.checkCircularDefinition(name, arg, visited);
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
/** Expand a definition by name with given arguments */
|
|
1561
|
+
expandDefinition(name, args) {
|
|
1562
|
+
const def = this.definitions.get(name);
|
|
1563
|
+
if (!def)
|
|
1564
|
+
return null;
|
|
1565
|
+
// If definition has no params, return body directly
|
|
1566
|
+
if (!def.params || def.params.length === 0) {
|
|
1567
|
+
return def.body;
|
|
1568
|
+
}
|
|
1569
|
+
// Substitute params with args
|
|
1570
|
+
const actualArgs = args ?? [];
|
|
1571
|
+
return this.substituteParams(def.body, def.params, actualArgs);
|
|
1572
|
+
}
|
|
1573
|
+
/** Recursively substitute parameter names with actual argument formulas */
|
|
1574
|
+
substituteParams(formula, params, args) {
|
|
1575
|
+
if (!formula)
|
|
1576
|
+
return formula;
|
|
1577
|
+
if (formula.kind === 'atom' && formula.name) {
|
|
1578
|
+
const idx = params.indexOf(formula.name);
|
|
1579
|
+
if (idx >= 0 && idx < args.length) {
|
|
1580
|
+
return args[idx];
|
|
1581
|
+
}
|
|
1582
|
+
return formula;
|
|
1583
|
+
}
|
|
1584
|
+
if (formula.args && formula.args.length > 0) {
|
|
1585
|
+
const newArgs = formula.args.map((a) => (a ? this.substituteParams(a, params, args) : a));
|
|
1586
|
+
let changed = false;
|
|
1587
|
+
for (let i = 0; i < formula.args.length; i++) {
|
|
1588
|
+
if (formula.args[i] !== newArgs[i]) {
|
|
1589
|
+
changed = true;
|
|
1590
|
+
break;
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
return changed ? { ...formula, args: newArgs } : formula;
|
|
1594
|
+
}
|
|
1595
|
+
return formula;
|
|
1596
|
+
}
|
|
1597
|
+
/** Expand all definitions in a formula (one level) */
|
|
1598
|
+
expandDefinitionsInFormula(f) {
|
|
1599
|
+
if (!f)
|
|
1600
|
+
return f;
|
|
1601
|
+
// If atom matches a definition name (no params), expand it
|
|
1602
|
+
if (f.kind === 'atom' && f.name) {
|
|
1603
|
+
const expanded = this.expandDefinition(f.name);
|
|
1604
|
+
if (expanded)
|
|
1605
|
+
return expanded;
|
|
1606
|
+
}
|
|
1607
|
+
// If it's a predicate-like call (name with args), try to expand parametric definition
|
|
1608
|
+
if (f.kind === 'predicate' && f.name) {
|
|
1609
|
+
const def = this.definitions.get(f.name);
|
|
1610
|
+
if (def && def.params && def.params.length > 0 && f.args) {
|
|
1611
|
+
const expanded = this.expandDefinition(f.name, f.args);
|
|
1612
|
+
if (expanded)
|
|
1613
|
+
return expanded;
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
// Recurse into sub-formulas
|
|
1617
|
+
if (f.args && f.args.length > 0) {
|
|
1618
|
+
const newArgs = f.args.map((a) => (a ? this.expandDefinitionsInFormula(a) : a));
|
|
1619
|
+
let changed = false;
|
|
1620
|
+
for (let i = 0; i < f.args.length; i++) {
|
|
1621
|
+
if (f.args[i] !== newArgs[i]) {
|
|
1622
|
+
changed = true;
|
|
1623
|
+
break;
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
return changed ? { ...f, args: newArgs } : f;
|
|
1627
|
+
}
|
|
1628
|
+
return f;
|
|
1629
|
+
}
|
|
1630
|
+
/** Try to fold a formula back into a definition reference */
|
|
1631
|
+
foldFormula(f) {
|
|
1632
|
+
const fStr = (0, propositional_1.formulaToString)(f);
|
|
1633
|
+
for (const [name, def] of this.definitions) {
|
|
1634
|
+
if (!def.params || def.params.length === 0) {
|
|
1635
|
+
const defStr = (0, propositional_1.formulaToString)(def.body);
|
|
1636
|
+
if (fStr === defStr) {
|
|
1637
|
+
return { kind: 'atom', name, source: f.source };
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
return f;
|
|
1642
|
+
}
|
|
1643
|
+
execUnfoldCmd(stmt) {
|
|
1644
|
+
const resolved = this.resolveFormulaRecursive(stmt.formula, new Set());
|
|
1645
|
+
const expanded = this.expandDefinitionsInFormula(resolved);
|
|
1646
|
+
const expandedStr = (0, format_1.formulaToUnicode)(expanded);
|
|
1647
|
+
this.emit(`Unfold: ${(0, format_1.formulaToUnicode)(resolved)} → ${expandedStr}`);
|
|
1648
|
+
this.results.push({
|
|
1649
|
+
status: 'valid',
|
|
1650
|
+
output: expandedStr,
|
|
1651
|
+
diagnostics: [],
|
|
1652
|
+
formula: expanded,
|
|
1653
|
+
});
|
|
1654
|
+
}
|
|
1655
|
+
execFoldCmd(stmt) {
|
|
1656
|
+
const resolved = this.resolveFormulaRecursive(stmt.formula, new Set());
|
|
1657
|
+
const folded = this.foldFormula(resolved);
|
|
1658
|
+
const foldedStr = (0, format_1.formulaToUnicode)(folded);
|
|
1659
|
+
this.emit(`Fold: ${(0, format_1.formulaToUnicode)(resolved)} → ${foldedStr}`);
|
|
1660
|
+
this.results.push({
|
|
1661
|
+
status: 'valid',
|
|
1662
|
+
output: foldedStr,
|
|
1663
|
+
diagnostics: [],
|
|
1664
|
+
formula: folded,
|
|
1665
|
+
});
|
|
1666
|
+
}
|
|
1667
|
+
execSourceDecl(stmt) {
|
|
1668
|
+
const info = { id: stmt.name };
|
|
1669
|
+
for (const field of stmt.fields) {
|
|
1670
|
+
switch (field.key) {
|
|
1671
|
+
case 'author':
|
|
1672
|
+
info.author = String(field.value);
|
|
1673
|
+
break;
|
|
1674
|
+
case 'work':
|
|
1675
|
+
info.work = String(field.value);
|
|
1676
|
+
break;
|
|
1677
|
+
case 'year':
|
|
1678
|
+
info.year = typeof field.value === 'number' ? field.value : parseInt(String(field.value));
|
|
1679
|
+
break;
|
|
1680
|
+
case 'section':
|
|
1681
|
+
info.section = String(field.value);
|
|
1682
|
+
break;
|
|
1683
|
+
case 'edition':
|
|
1684
|
+
info.edition = String(field.value);
|
|
1685
|
+
break;
|
|
1686
|
+
case 'url':
|
|
1687
|
+
info.url = String(field.value);
|
|
1688
|
+
break;
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
this.sources.set(stmt.name, info);
|
|
1692
|
+
const diags = (0, compiler_1.registerSource)(this.textLayer, info);
|
|
1693
|
+
this.diagnostics.push(...diags);
|
|
1694
|
+
const yearStr = info.year ? ` (${info.year})` : '';
|
|
1695
|
+
this.emit(`Source ${stmt.name}: ${info.author ?? ''}${yearStr} — ${info.work ?? ''}`);
|
|
1696
|
+
}
|
|
1697
|
+
execInterpretCmd(stmt) {
|
|
1698
|
+
const formula = this.resolveFormula(stmt.formula);
|
|
1699
|
+
const key = stmt.passageRef ?? stmt.text;
|
|
1700
|
+
const diags = (0, compiler_1.registerInterpretation)(this.textLayer, key, {
|
|
1701
|
+
text: stmt.text,
|
|
1702
|
+
passageRef: stmt.passageRef,
|
|
1703
|
+
formula,
|
|
1704
|
+
});
|
|
1705
|
+
this.diagnostics.push(...diags);
|
|
1706
|
+
// Also register as a let binding so the interpretation is available as a named formula
|
|
1707
|
+
const bindingName = stmt.text.replace(/\s+/g, '_').replace(/[^a-zA-Z0-9_]/g, '');
|
|
1708
|
+
if (bindingName) {
|
|
1709
|
+
this.defineBinding(bindingName, formula);
|
|
1710
|
+
}
|
|
1711
|
+
this.emit(`Interpret: "${stmt.text}" → ${(0, format_1.formulaToUnicode)(formula)}`);
|
|
1712
|
+
}
|
|
1713
|
+
execGlossaryCmd(_stmt) {
|
|
1714
|
+
this.emit('');
|
|
1715
|
+
this.emit('══════════════════════════════════════');
|
|
1716
|
+
this.emit(' GLOSARIO');
|
|
1717
|
+
this.emit('══════════════════════════════════════');
|
|
1718
|
+
if (this.definitions.size === 0) {
|
|
1719
|
+
this.emit(' (sin definiciones registradas)');
|
|
1720
|
+
}
|
|
1721
|
+
else {
|
|
1722
|
+
for (const [name, def] of this.definitions) {
|
|
1723
|
+
const paramsStr = def.params?.length ? `(${def.params.join(', ')})` : '';
|
|
1724
|
+
const bodyStr = (0, format_1.formulaToUnicode)(def.body);
|
|
1725
|
+
this.emit(` ${name}${paramsStr} := ${bodyStr}`);
|
|
1726
|
+
if (def.description) {
|
|
1727
|
+
this.emit(` "${def.description}"`);
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
// Also show sources if any
|
|
1732
|
+
if (this.sources.size > 0) {
|
|
1733
|
+
this.emit('');
|
|
1734
|
+
this.emit('── Fuentes ──');
|
|
1735
|
+
for (const [, src] of this.sources) {
|
|
1736
|
+
const yearStr = src.year ? ` (${src.year})` : '';
|
|
1737
|
+
this.emit(` ${src.id}: ${src.author ?? ''}${yearStr} — ${src.work ?? ''}`);
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1740
|
+
// Show interpretations if any
|
|
1741
|
+
if (this.textLayer.interpretations.size > 0) {
|
|
1742
|
+
this.emit('');
|
|
1743
|
+
this.emit('── Interpretaciones ──');
|
|
1744
|
+
for (const [, interp] of this.textLayer.interpretations) {
|
|
1745
|
+
this.emit(` "${interp.text}" → ${(0, format_1.formulaToUnicode)(interp.formula)}`);
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
this.emit('══════════════════════════════════════');
|
|
1749
|
+
this.emit('');
|
|
1750
|
+
}
|
|
1751
|
+
// ── End v3 ─────────────────────────────────────────────────
|
|
1344
1752
|
executeFnCall(stmt) {
|
|
1345
1753
|
// ── Memoización: verificar cache antes de ejecutar ──
|
|
1346
1754
|
const evaluatedArgs = stmt.args.map((a) => this.evaluateFormulaValue(a));
|