@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.
Files changed (45) hide show
  1. package/dist/{analyzer-DlSq3Y3r.d.ts → analyzer-BliNe3pV.d.ts} +2 -2
  2. package/dist/{ast-annotations-BiMjkKvz.d.ts → ast-annotations-GOkbNN8F.d.ts} +2 -2
  3. package/dist/{calculator-C9W2jkSx.d.ts → calculator-DFevxZyV.d.ts} +3 -3
  4. package/dist/{error-E1LVq_3w.d.ts → error-deey7EiC.d.ts} +2 -1
  5. package/dist/index.d.ts +6 -6
  6. package/dist/index.js +1 -1
  7. package/dist/library/rsengine.d.ts +2 -3
  8. package/dist/library/rsengine.js +15 -43
  9. package/dist/library/rsengine.js.map +1 -1
  10. package/dist/library/rsform-api.d.ts +1 -1
  11. package/dist/library/rsform.d.ts +1 -1
  12. package/dist/library/rsmodel-api.d.ts +1 -1
  13. package/dist/library/rsmodel-api.js +1 -1
  14. package/dist/library/rsmodel.d.ts +1 -1
  15. package/dist/rslang/ast-annotations.d.ts +1 -1
  16. package/dist/rslang/error.d.ts +1 -1
  17. package/dist/rslang/error.js +1 -0
  18. package/dist/rslang/error.js.map +1 -1
  19. package/dist/rslang/eval/calculator.d.ts +1 -1
  20. package/dist/rslang/eval/calculator.js +1 -1
  21. package/dist/rslang/eval/evaluation-cache.d.ts +1 -1
  22. package/dist/rslang/eval/evaluator.d.ts +2 -2
  23. package/dist/rslang/eval/evaluator.js +17 -11
  24. package/dist/rslang/eval/evaluator.js.map +1 -1
  25. package/dist/rslang/eval/value-api.d.ts +1 -1
  26. package/dist/rslang/eval/value-api.js +1 -1
  27. package/dist/rslang/eval/value.d.ts +2 -2
  28. package/dist/rslang/eval/value.js +2 -2
  29. package/dist/rslang/index.d.ts +6 -6
  30. package/dist/rslang/index.js +1 -1
  31. package/dist/rslang/parser/syntax-errors.d.ts +1 -1
  32. package/dist/rslang/semantic/analyzer.d.ts +1 -1
  33. package/dist/rslang/semantic/type-auditor.d.ts +1 -1
  34. package/dist/rslang/semantic/value-auditor.d.ts +1 -1
  35. package/dist/{value-CTjX6825.d.ts → value-BduA_ZGp.d.ts} +8 -2
  36. package/dist/{value-api-Bw-SgaYY.d.ts → value-api-B6T6f4Ia.d.ts} +2 -2
  37. package/dist/{value-B8UtCqaK.js → value-ybFBRuz6.js} +14 -3
  38. package/dist/{value-B8UtCqaK.js.map → value-ybFBRuz6.js.map} +1 -1
  39. package/package.json +1 -1
  40. package/src/library/rsengine.ts +14 -59
  41. package/src/rslang/error.ts +1 -0
  42. package/src/rslang/eval/calculator.test.ts +8 -0
  43. package/src/rslang/eval/evaluator.test.ts +5 -1
  44. package/src/rslang/eval/evaluator.ts +22 -13
  45. 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
- const result = this.dispatchVisitImpl(node);
157
- if (!this.disableCache && result !== null && info.cacheable && stamp !== null) {
158
- this.evalCache.store(info.structuralKey, stamp, result);
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 === undefined) {
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
- return this.locals.getLocal(alias);
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
- getLocal(alias: string): Value {
914
- const binding = this.data.get(alias);
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 {
@@ -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 Error(`Cannot compare different types ${printValue(el1!)} and ${printValue(el2!)}`);
80
+ throw new CalcInvalidDataError(printValue(el1!), printValue(el2!));
68
81
  }
69
82
 
70
83
  const arr1 = el1;