@rsconcept/domain 1.3.0 → 1.4.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/dist/{analyzer-DlSq3Y3r.d.ts → analyzer-BliNe3pV.d.ts} +2 -2
- package/dist/{ast-annotations-BiMjkKvz.d.ts → ast-annotations-GOkbNN8F.d.ts} +2 -2
- package/dist/{calculator-C9W2jkSx.d.ts → calculator-DFevxZyV.d.ts} +3 -3
- package/dist/{error-E1LVq_3w.d.ts → error-deey7EiC.d.ts} +2 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.js +1 -1
- package/dist/library/rsengine.d.ts +2 -3
- package/dist/library/rsengine.js +15 -43
- package/dist/library/rsengine.js.map +1 -1
- package/dist/library/rsform-api.d.ts +1 -1
- package/dist/library/rsform.d.ts +1 -1
- package/dist/library/rsmodel-api.d.ts +1 -1
- package/dist/library/rsmodel-api.js +1 -1
- package/dist/library/rsmodel.d.ts +1 -1
- package/dist/rslang/ast-annotations.d.ts +1 -1
- package/dist/rslang/error.d.ts +1 -1
- package/dist/rslang/error.js +1 -0
- package/dist/rslang/error.js.map +1 -1
- package/dist/rslang/eval/calculator.d.ts +1 -1
- package/dist/rslang/eval/calculator.js +1 -1
- package/dist/rslang/eval/evaluation-cache.d.ts +1 -1
- package/dist/rslang/eval/evaluator.d.ts +2 -2
- package/dist/rslang/eval/evaluator.js +17 -11
- package/dist/rslang/eval/evaluator.js.map +1 -1
- package/dist/rslang/eval/value-api.d.ts +1 -1
- package/dist/rslang/eval/value-api.js +1 -1
- package/dist/rslang/eval/value.d.ts +2 -2
- package/dist/rslang/eval/value.js +2 -2
- package/dist/rslang/index.d.ts +6 -6
- package/dist/rslang/index.js +1 -1
- package/dist/rslang/parser/syntax-errors.d.ts +1 -1
- package/dist/rslang/semantic/analyzer.d.ts +1 -1
- package/dist/rslang/semantic/type-auditor.d.ts +1 -1
- package/dist/rslang/semantic/value-auditor.d.ts +1 -1
- package/dist/{value-CTjX6825.d.ts → value-BduA_ZGp.d.ts} +8 -2
- package/dist/{value-api-Bw-SgaYY.d.ts → value-api-B6T6f4Ia.d.ts} +2 -2
- package/dist/{value-B8UtCqaK.js → value-ybFBRuz6.js} +14 -3
- package/dist/{value-B8UtCqaK.js.map → value-ybFBRuz6.js.map} +1 -1
- package/package.json +1 -1
- package/src/library/rsengine.ts +14 -59
- package/src/rslang/error.ts +1 -0
- package/src/rslang/eval/calculator.test.ts +8 -0
- package/src/rslang/eval/evaluator.test.ts +5 -1
- package/src/rslang/eval/evaluator.ts +22 -13
- package/src/rslang/eval/value.ts +14 -1
|
@@ -73,6 +73,14 @@ describe('RSCalculator', () => {
|
|
|
73
73
|
expectCalcFull('X11', { expectErrorCode: RSErrorCode.calcGlobalMissing });
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
+
it('returns error for undeclared local variable', () => {
|
|
77
|
+
expectCalcFull('∀a∈X1 b=b', { expectErrorCode: RSErrorCode.localUndeclared });
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('returns error for incompatible value comparison', () => {
|
|
81
|
+
expectCalcFull('X1=1', { expectErrorCode: RSErrorCode.calcInvalidData });
|
|
82
|
+
});
|
|
83
|
+
|
|
76
84
|
it('returns error for infinite quantifier', () => {
|
|
77
85
|
expectCalcFull('∀a∈Z a=a', { expectErrorCode: RSErrorCode.iterateInfinity });
|
|
78
86
|
});
|
|
@@ -192,6 +192,7 @@ const correctValuesData = [
|
|
|
192
192
|
const errorData = [
|
|
193
193
|
['[a∈ℬ(R1)] a=a', { code: RSErrorCode.calculationNotSupported, from: 0, to: 13 }],
|
|
194
194
|
['debool(X1)', { code: RSErrorCode.calcInvalidDebool, from: 7, to: 9 }],
|
|
195
|
+
['Pr1(1)', { code: RSErrorCode.calcUnknownError, from: 0, to: 6 }],
|
|
195
196
|
['∀a∈Z a=a', { code: RSErrorCode.iterateInfinity, from: 3, to: 4 }],
|
|
196
197
|
['ℬℬ({1,2,3,4,5})', { code: RSErrorCode.booleanBaseLimit, from: 1, to: 15, params: [String(BOOL_INFINITY)] }],
|
|
197
198
|
['X1\\D1', { code: RSErrorCode.calcGlobalMissing, from: 3, to: 5, params: ['D1'] }],
|
|
@@ -227,7 +228,10 @@ const errorData = [
|
|
|
227
228
|
['R{a:=X1 | D1=D1 | a∪X1}', { code: RSErrorCode.calcGlobalMissing, from: 10, to: 12, params: ['D1'] }],
|
|
228
229
|
['I{(a,b) | a:∈D1; b:=a; b≠a}', { code: RSErrorCode.calcGlobalMissing, from: 13, to: 15, params: ['D1'] }],
|
|
229
230
|
['I{(a,b) | a:∈X1; b:=a; b≠D1}', { code: RSErrorCode.calcGlobalMissing, from: 25, to: 27, params: ['D1'] }],
|
|
230
|
-
['I{(a,b) | a:∈X1; b:=D1; b≠a}', { code: RSErrorCode.calcGlobalMissing, from: 20, to: 22, params: ['D1'] }]
|
|
231
|
+
['I{(a,b) | a:∈X1; b:=D1; b≠a}', { code: RSErrorCode.calcGlobalMissing, from: 20, to: 22, params: ['D1'] }],
|
|
232
|
+
['∀a∈X1 b=b', { code: RSErrorCode.localUndeclared, from: 6, to: 7, params: ['b'] }],
|
|
233
|
+
['X1=1', { code: RSErrorCode.calcInvalidData, from: 0, to: 4, params: ['{1, 2, 3}', '1'] }],
|
|
234
|
+
['X1=1 & 1=1', { code: RSErrorCode.calcInvalidData, from: 0, to: 4, params: ['{1, 2, 3}', '1'] }]
|
|
231
235
|
];
|
|
232
236
|
|
|
233
237
|
describe('Calculator', () => {
|
|
@@ -10,6 +10,7 @@ import { TokenID } from '../parser/token';
|
|
|
10
10
|
import { EvaluationCache, EvaluationMetadata } from './evaluation-cache';
|
|
11
11
|
import {
|
|
12
12
|
BOOL_INFINITY,
|
|
13
|
+
CalcInvalidDataError,
|
|
13
14
|
compare,
|
|
14
15
|
EmptySetV,
|
|
15
16
|
set,
|
|
@@ -153,11 +154,19 @@ export class Evaluator {
|
|
|
153
154
|
}
|
|
154
155
|
}
|
|
155
156
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
this.
|
|
157
|
+
try {
|
|
158
|
+
const result = this.dispatchVisitImpl(node);
|
|
159
|
+
if (!this.disableCache && result !== null && info.cacheable && stamp !== null) {
|
|
160
|
+
this.evalCache.store(info.structuralKey, stamp, result);
|
|
161
|
+
}
|
|
162
|
+
return result;
|
|
163
|
+
} catch (error) {
|
|
164
|
+
if (error instanceof CalcInvalidDataError) {
|
|
165
|
+
return this.onError(RSErrorCode.calcInvalidData, node, [error.left, error.right]);
|
|
166
|
+
}
|
|
167
|
+
this.onError(RSErrorCode.calcUnknownError, node);
|
|
168
|
+
return null;
|
|
159
169
|
}
|
|
160
|
-
return result;
|
|
161
170
|
}
|
|
162
171
|
|
|
163
172
|
private dispatchVisitImpl(node: AstNode): Value | null {
|
|
@@ -280,8 +289,8 @@ export class Evaluator {
|
|
|
280
289
|
|
|
281
290
|
private visitGlobal(node: AstNode): Value | null {
|
|
282
291
|
const alias = getNodeText(node);
|
|
283
|
-
const value = this.context.get(alias);
|
|
284
|
-
if (value ===
|
|
292
|
+
const value = this.context.get(alias) ?? null;
|
|
293
|
+
if (value === null) {
|
|
285
294
|
return this.onError(RSErrorCode.calcGlobalMissing, node, [alias]);
|
|
286
295
|
}
|
|
287
296
|
return value;
|
|
@@ -289,7 +298,11 @@ export class Evaluator {
|
|
|
289
298
|
|
|
290
299
|
private visitLocal(node: AstNode): Value | null {
|
|
291
300
|
const alias = getNodeText(node);
|
|
292
|
-
|
|
301
|
+
const value = this.locals.findLocal(alias);
|
|
302
|
+
if (value === null) {
|
|
303
|
+
return this.onError(RSErrorCode.localUndeclared, node, [alias]);
|
|
304
|
+
}
|
|
305
|
+
return value;
|
|
293
306
|
}
|
|
294
307
|
|
|
295
308
|
private visitFunctionCall(node: AstNode): Value | null {
|
|
@@ -910,12 +923,8 @@ class LocalContext {
|
|
|
910
923
|
}
|
|
911
924
|
}
|
|
912
925
|
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
if (binding === undefined) {
|
|
916
|
-
throw new Error(`Local variable "${alias}" not found`);
|
|
917
|
-
}
|
|
918
|
-
return binding.value;
|
|
926
|
+
findLocal(alias: string): Value | null {
|
|
927
|
+
return this.data.get(alias)?.value ?? null;
|
|
919
928
|
}
|
|
920
929
|
|
|
921
930
|
buildDependencyStamp(reads: ReadonlySet<string>): string | null {
|
package/src/rslang/eval/value.ts
CHANGED
|
@@ -41,6 +41,19 @@ export function makeValuePath(path: number[]): ValuePath {
|
|
|
41
41
|
/** Empty set ∅. */
|
|
42
42
|
export const EmptySetV = [];
|
|
43
43
|
|
|
44
|
+
/** Thrown when a runtime value operation cannot be applied to the given operands. */
|
|
45
|
+
export class CalcInvalidDataError extends Error {
|
|
46
|
+
readonly left: string;
|
|
47
|
+
readonly right: string;
|
|
48
|
+
|
|
49
|
+
constructor(left: string, right: string) {
|
|
50
|
+
super(`Cannot compare different types ${left} and ${right}`);
|
|
51
|
+
this.name = 'CalcInvalidDataError';
|
|
52
|
+
this.left = left;
|
|
53
|
+
this.right = right;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
44
57
|
/** Compare two structured data without recursive calls. */
|
|
45
58
|
export function compare(v1: Value, v2: Value): number {
|
|
46
59
|
const stack1: Value[] = [v1];
|
|
@@ -64,7 +77,7 @@ export function compare(v1: Value, v2: Value): number {
|
|
|
64
77
|
const isArray1 = Array.isArray(el1);
|
|
65
78
|
const isArray2 = Array.isArray(el2);
|
|
66
79
|
if (!isArray1 || !isArray2) {
|
|
67
|
-
throw new
|
|
80
|
+
throw new CalcInvalidDataError(printValue(el1!), printValue(el2!));
|
|
68
81
|
}
|
|
69
82
|
|
|
70
83
|
const arr1 = el1;
|