@rsconcept/domain 1.5.2 → 1.6.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/{analyzer-0kmNRqcr.d.ts → analyzer-camCAEkQ.d.ts} +2 -2
- package/dist/{ast-annotations-BnVekMjH.d.ts → ast-annotations-DiXmFraa.d.ts} +2 -2
- package/dist/{calculator-OV-RNXre.d.ts → calculator-BuVooqpb.d.ts} +2 -2
- package/dist/{error-DYLkv4B3.d.ts → error-CZXO5Y6a.d.ts} +7 -3
- package/dist/index.d.ts +4 -4
- package/dist/library/rsengine.d.ts +1 -1
- package/dist/library/rsform-api.d.ts +1 -1
- package/dist/library/rsform-api.js +2 -1
- package/dist/library/rsform-api.js.map +1 -1
- package/dist/library/rsform.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 +6 -2
- package/dist/rslang/error.js.map +1 -1
- package/dist/rslang/eval/calculator.d.ts +1 -1
- package/dist/rslang/eval/evaluator.d.ts +1 -1
- package/dist/rslang/index.d.ts +4 -4
- package/dist/rslang/parser/syntax-errors.d.ts +1 -1
- package/dist/rslang/parser/syntax-errors.js +44 -0
- package/dist/rslang/parser/syntax-errors.js.map +1 -1
- package/dist/rslang/semantic/analyzer.d.ts +1 -1
- package/dist/rslang/semantic/analyzer.js +5 -2
- package/dist/rslang/semantic/analyzer.js.map +1 -1
- package/dist/rslang/semantic/type-auditor.d.ts +1 -1
- package/dist/rslang/semantic/type-auditor.js +32 -11
- package/dist/rslang/semantic/type-auditor.js.map +1 -1
- package/dist/rslang/semantic/value-auditor.d.ts +1 -1
- package/package.json +1 -1
- package/src/library/rsform-api.test.ts +30 -2
- package/src/library/rsform-api.ts +2 -1
- package/src/rslang/error.ts +6 -2
- package/src/rslang/parser/parser.test.ts +21 -0
- package/src/rslang/parser/syntax-errors.ts +63 -0
- package/src/rslang/semantic/analyzer.test.ts +56 -6
- package/src/rslang/semantic/analyzer.ts +5 -2
- package/src/rslang/semantic/type-auditor.test.ts +17 -7
- package/src/rslang/semantic/type-auditor.ts +31 -22
|
@@ -45,15 +45,65 @@ describe('RSLang analyzer', () => {
|
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
it('Expected type', () => {
|
|
48
|
-
expectError(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
expectError(
|
|
49
|
+
'X1',
|
|
50
|
+
{ expected: TypeClass.logic },
|
|
51
|
+
{
|
|
52
|
+
code: RSErrorCode.expectedType,
|
|
53
|
+
from: 0,
|
|
54
|
+
to: 2,
|
|
55
|
+
params: [String(TypeClass.logic), labelType(bool(basic('X1')))]
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
expectError(
|
|
59
|
+
'1=1',
|
|
60
|
+
{ expected: TypeClass.typification },
|
|
61
|
+
{
|
|
62
|
+
code: RSErrorCode.expectedType,
|
|
63
|
+
from: 0,
|
|
64
|
+
to: 3,
|
|
65
|
+
params: [String(TypeClass.typification), 'Logic']
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
expectError(
|
|
69
|
+
'1=1',
|
|
70
|
+
{ expected: TypeClass.function },
|
|
71
|
+
{
|
|
72
|
+
code: RSErrorCode.expectedType,
|
|
73
|
+
from: 0,
|
|
74
|
+
to: 3,
|
|
75
|
+
params: [String(TypeClass.function), 'Logic']
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
expectError(
|
|
79
|
+
'[a ∈ X1] a=a',
|
|
80
|
+
{ expected: TypeClass.function },
|
|
81
|
+
{
|
|
82
|
+
code: RSErrorCode.expectedType,
|
|
83
|
+
from: 0,
|
|
84
|
+
to: 12,
|
|
85
|
+
params: [String(TypeClass.function), '[X1] → Logic']
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
expectError(
|
|
89
|
+
'[a ∈ X1] a',
|
|
90
|
+
{ expected: TypeClass.predicate },
|
|
91
|
+
{
|
|
92
|
+
code: RSErrorCode.expectedType,
|
|
93
|
+
from: 0,
|
|
94
|
+
to: 10,
|
|
95
|
+
params: [String(TypeClass.predicate), '[X1] → X1']
|
|
96
|
+
}
|
|
97
|
+
);
|
|
53
98
|
});
|
|
54
99
|
|
|
55
100
|
it('Reports analyzer-level ranges for whole-expression errors', () => {
|
|
56
101
|
const result = analyzer.checkFull('X1', { expected: TypeClass.logic });
|
|
57
|
-
expect(result.errors[0]).toMatchObject({
|
|
102
|
+
expect(result.errors[0]).toMatchObject({
|
|
103
|
+
code: RSErrorCode.expectedType,
|
|
104
|
+
from: 0,
|
|
105
|
+
to: 2,
|
|
106
|
+
params: [String(TypeClass.logic), labelType(bool(basic('X1')))]
|
|
107
|
+
});
|
|
58
108
|
});
|
|
59
109
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type AstNode, buildTree } from '../../parsing';
|
|
2
2
|
import { annotateError } from '../ast-annotations';
|
|
3
3
|
import { RSErrorCode, type RSErrorDescription } from '../error';
|
|
4
|
+
import { labelType } from '../labels';
|
|
4
5
|
import { normalizeAST } from '../parser/normalize';
|
|
5
6
|
import { parser as rslangParser } from '../parser/parser';
|
|
6
7
|
import { extractSyntaxErrors } from '../parser/syntax-errors';
|
|
@@ -136,13 +137,15 @@ export class RSLangAnalyzer {
|
|
|
136
137
|
return { success: true, type: debool(type), valueClass: ValueClass.VALUE, errors, ast };
|
|
137
138
|
}
|
|
138
139
|
if (options?.expected && getTypeClass(type.typeID) !== options.expected) {
|
|
140
|
+
const errorParams = [String(options.expected), labelType(type)];
|
|
139
141
|
reporter({
|
|
140
142
|
code: RSErrorCode.expectedType,
|
|
141
143
|
from: ast.from,
|
|
142
|
-
to: ast.to
|
|
144
|
+
to: ast.to,
|
|
145
|
+
params: errorParams
|
|
143
146
|
});
|
|
144
147
|
if (options?.annotateErrors) {
|
|
145
|
-
annotateError(ast, RSErrorCode.expectedType);
|
|
148
|
+
annotateError(ast, RSErrorCode.expectedType, errorParams);
|
|
146
149
|
}
|
|
147
150
|
return { success: false, type: null, valueClass: null, errors, ast };
|
|
148
151
|
}
|
|
@@ -185,6 +185,7 @@ const errorData = [
|
|
|
185
185
|
['∀a∈X1 a=a & a=a', { code: RSErrorCode.localOutOfScopeParentheses, from: 12, to: 13, params: ['a'] }],
|
|
186
186
|
['∀a∈X1 a=a & debool(X1)=a', { code: RSErrorCode.localOutOfScopeParentheses, from: 23, to: 24, params: ['a'] }],
|
|
187
187
|
['∀ξ∈X1 ξ=ξ & ∀φ∈X1 φ=ξ', { code: RSErrorCode.localUndeclaredInSubexpr, from: 20, to: 21, params: ['ξ', 'X1'] }],
|
|
188
|
+
['∀ξ∈X1 ξ=ξ & (ξ=ξ & ∀φ∈X1 φ=φ)', { code: RSErrorCode.localOutOfScopeParentheses, from: 13, to: 14, params: ['ξ'] }],
|
|
188
189
|
['D{t∈X1 | t=t} ∪ {t}', { code: RSErrorCode.localOutOfScope, from: 17, to: 18, params: ['t'] }],
|
|
189
190
|
// Set predicates
|
|
190
191
|
['X1∈X1', { code: RSErrorCode.invalidElementPredicate, from: 0, to: 5, params: ['ℬ(X1)', '∈', 'ℬ(X1)'] }],
|
|
@@ -213,13 +214,22 @@ const errorData = [
|
|
|
213
214
|
['X1 ∪ ∅', { code: RSErrorCode.invalidEmptySetUsage, from: 5, to: 6 }],
|
|
214
215
|
['X1 ∪ S1', { code: RSErrorCode.typesNotEqual, from: 0, to: 7, params: ['ℬ(X1)', 'ℬ(X1×X1)', '∪'] }],
|
|
215
216
|
['S1 ∪ X1', { code: RSErrorCode.typesNotEqual, from: 0, to: 7, params: ['ℬ(X1×X1)', 'ℬ(X1)', '∪'] }],
|
|
216
|
-
['Pr1(X1)', { code: RSErrorCode.
|
|
217
|
-
[
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
[
|
|
222
|
-
|
|
217
|
+
['Pr1(X1)', { code: RSErrorCode.projectionSetArgumentNotTupleSet, from: 4, to: 6, params: ['Pr1', 'ℬ(X1)'] }],
|
|
218
|
+
[
|
|
219
|
+
'Pr3(S1)',
|
|
220
|
+
{ code: RSErrorCode.projectionSetIndexOutOfRange, from: 4, to: 6, params: ['Pr3', '3', '2', 'ℬ(X1×X1)'] }
|
|
221
|
+
],
|
|
222
|
+
[
|
|
223
|
+
'Pr1,3(S1)',
|
|
224
|
+
{ code: RSErrorCode.projectionSetIndexOutOfRange, from: 6, to: 8, params: ['Pr1,3', '3', '2', 'ℬ(X1×X1)'] }
|
|
225
|
+
],
|
|
226
|
+
['Pr1((1,2))', { code: RSErrorCode.projectionSetArgumentNotSet, from: 4, to: 9, params: ['Pr1', 'Z×Z'] }],
|
|
227
|
+
['pr1(X1)', { code: RSErrorCode.projectionTupleArgumentNotTuple, from: 4, to: 6, params: ['pr1', 'ℬ(X1)'] }],
|
|
228
|
+
['pr1(debool(X1))', { code: RSErrorCode.projectionTupleArgumentNotTuple, from: 4, to: 14, params: ['pr1', 'X1'] }],
|
|
229
|
+
[
|
|
230
|
+
'pr3(debool(S1))',
|
|
231
|
+
{ code: RSErrorCode.projectionTupleIndexOutOfRange, from: 4, to: 14, params: ['pr3', '3', '2', 'X1×X1'] }
|
|
232
|
+
],
|
|
223
233
|
[
|
|
224
234
|
'Fi1[X1](ℬ(X1))',
|
|
225
235
|
{ code: RSErrorCode.invalidFilterArgumentType, from: 8, to: 13, params: ['Fi1', 'ℬℬ(X1)', 'ℬ(R0)'] }
|
|
@@ -673,18 +673,21 @@ export class TypeAuditor {
|
|
|
673
673
|
}
|
|
674
674
|
|
|
675
675
|
private visitProjectSet(node: AstNode): ExpressionType | null {
|
|
676
|
-
const
|
|
677
|
-
|
|
676
|
+
const operator = labelRSLangNode(node);
|
|
677
|
+
const argNode = node.children[0];
|
|
678
|
+
const argType = this.childTypification(node, 0);
|
|
679
|
+
if (argType === null) {
|
|
678
680
|
return null;
|
|
679
681
|
}
|
|
680
|
-
if (
|
|
682
|
+
if (argType.typeID === TypeID.anyTypification) {
|
|
681
683
|
return EmptySetT;
|
|
682
684
|
}
|
|
685
|
+
if (argType.typeID !== TypeID.collection) {
|
|
686
|
+
return this.onError(RSErrorCode.projectionSetArgumentNotSet, argNode, [operator, labelType(argType)]);
|
|
687
|
+
}
|
|
688
|
+
const argument = debool(argType);
|
|
683
689
|
if (argument.typeID !== TypeID.tuple) {
|
|
684
|
-
return this.onError(RSErrorCode.
|
|
685
|
-
labelRSLangNode(node),
|
|
686
|
-
labelType(bool(argument))
|
|
687
|
-
]);
|
|
690
|
+
return this.onError(RSErrorCode.projectionSetArgumentNotTupleSet, argNode, [operator, labelType(bool(argument))]);
|
|
688
691
|
}
|
|
689
692
|
|
|
690
693
|
const indices = getNodeIndices(node);
|
|
@@ -692,8 +695,10 @@ export class TypeAuditor {
|
|
|
692
695
|
for (const index of indices) {
|
|
693
696
|
const newComponent = component(argument, index);
|
|
694
697
|
if (newComponent === null) {
|
|
695
|
-
return this.onError(RSErrorCode.
|
|
696
|
-
|
|
698
|
+
return this.onError(RSErrorCode.projectionSetIndexOutOfRange, argNode, [
|
|
699
|
+
operator,
|
|
700
|
+
String(index),
|
|
701
|
+
String(argument.factors.length),
|
|
697
702
|
labelType(bool(argument))
|
|
698
703
|
]);
|
|
699
704
|
} else {
|
|
@@ -708,6 +713,8 @@ export class TypeAuditor {
|
|
|
708
713
|
}
|
|
709
714
|
|
|
710
715
|
private visitProjectTuple(node: AstNode): ExpressionType | null {
|
|
716
|
+
const operator = labelRSLangNode(node);
|
|
717
|
+
const argNode = node.children[0];
|
|
711
718
|
const argument = this.childTypification(node, 0);
|
|
712
719
|
if (argument === null) {
|
|
713
720
|
return null;
|
|
@@ -716,10 +723,7 @@ export class TypeAuditor {
|
|
|
716
723
|
return argument;
|
|
717
724
|
}
|
|
718
725
|
if (argument.typeID !== TypeID.tuple) {
|
|
719
|
-
return this.onError(RSErrorCode.
|
|
720
|
-
labelRSLangNode(node),
|
|
721
|
-
labelType(argument)
|
|
722
|
-
]);
|
|
726
|
+
return this.onError(RSErrorCode.projectionTupleArgumentNotTuple, argNode, [operator, labelType(argument)]);
|
|
723
727
|
}
|
|
724
728
|
|
|
725
729
|
const indices = getNodeIndices(node);
|
|
@@ -727,8 +731,10 @@ export class TypeAuditor {
|
|
|
727
731
|
for (const index of indices) {
|
|
728
732
|
const newComponent = component(argument, index);
|
|
729
733
|
if (newComponent === null) {
|
|
730
|
-
return this.onError(RSErrorCode.
|
|
731
|
-
|
|
734
|
+
return this.onError(RSErrorCode.projectionTupleIndexOutOfRange, argNode, [
|
|
735
|
+
operator,
|
|
736
|
+
String(index),
|
|
737
|
+
String(argument.factors.length),
|
|
732
738
|
labelType(argument)
|
|
733
739
|
]);
|
|
734
740
|
} else {
|
|
@@ -1080,14 +1086,17 @@ function isQuantifierNode(typeID: number): boolean {
|
|
|
1080
1086
|
return typeID === TokenID.QUANTOR_UNIVERSAL || typeID === TokenID.QUANTOR_EXISTS;
|
|
1081
1087
|
}
|
|
1082
1088
|
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
if (subtreeContainsQuantifier(child)) {
|
|
1089
|
+
/** Quantifier on the path from `node` up through `stopAt` (inclusive). */
|
|
1090
|
+
function pathContainsQuantifier(node: AstNode, stopAt: AstNode): boolean {
|
|
1091
|
+
let current: AstNode | null = node;
|
|
1092
|
+
while (current !== null) {
|
|
1093
|
+
if (isQuantifierNode(current.typeID)) {
|
|
1089
1094
|
return true;
|
|
1090
1095
|
}
|
|
1096
|
+
if (current === stopAt) {
|
|
1097
|
+
return false;
|
|
1098
|
+
}
|
|
1099
|
+
current = current.parent;
|
|
1091
1100
|
}
|
|
1092
1101
|
return false;
|
|
1093
1102
|
}
|
|
@@ -1167,7 +1176,7 @@ class LocalContext {
|
|
|
1167
1176
|
} else if (local.level < 1) {
|
|
1168
1177
|
const subexprRoot = findRightLogicOperandRoot(node);
|
|
1169
1178
|
if (subexprRoot !== null) {
|
|
1170
|
-
if (
|
|
1179
|
+
if (pathContainsQuantifier(node, subexprRoot)) {
|
|
1171
1180
|
return this.onError(RSErrorCode.localUndeclaredInSubexpr, node, [alias, labelType(local.type)]);
|
|
1172
1181
|
}
|
|
1173
1182
|
return this.onError(RSErrorCode.localOutOfScopeParentheses, node, [alias]);
|