@rsconcept/domain 1.5.1 → 1.6.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 (34) hide show
  1. package/dist/{analyzer-Bx7SOXWN.d.ts → analyzer-A82AxKdS.d.ts} +2 -2
  2. package/dist/{ast-annotations-DBZCQOsx.d.ts → ast-annotations-YzvwjoFW.d.ts} +2 -2
  3. package/dist/{calculator-Dwv_yn2r.d.ts → calculator-Cyy9eYyx.d.ts} +2 -2
  4. package/dist/{error-CB3HYTri.d.ts → error-Cv4sntcy.d.ts} +8 -3
  5. package/dist/index.d.ts +4 -4
  6. package/dist/library/rsengine.d.ts +1 -1
  7. package/dist/library/rsform-api.d.ts +1 -1
  8. package/dist/library/rsform-api.js +2 -1
  9. package/dist/library/rsform-api.js.map +1 -1
  10. package/dist/library/rsform.d.ts +1 -1
  11. package/dist/rslang/ast-annotations.d.ts +1 -1
  12. package/dist/rslang/error.d.ts +1 -1
  13. package/dist/rslang/error.js +7 -2
  14. package/dist/rslang/error.js.map +1 -1
  15. package/dist/rslang/eval/calculator.d.ts +1 -1
  16. package/dist/rslang/eval/evaluator.d.ts +1 -1
  17. package/dist/rslang/index.d.ts +4 -4
  18. package/dist/rslang/parser/syntax-errors.d.ts +1 -1
  19. package/dist/rslang/semantic/analyzer.d.ts +1 -1
  20. package/dist/rslang/semantic/analyzer.js +5 -2
  21. package/dist/rslang/semantic/analyzer.js.map +1 -1
  22. package/dist/rslang/semantic/type-auditor.d.ts +1 -1
  23. package/dist/rslang/semantic/type-auditor.js +56 -7
  24. package/dist/rslang/semantic/type-auditor.js.map +1 -1
  25. package/dist/rslang/semantic/value-auditor.d.ts +1 -1
  26. package/package.json +1 -1
  27. package/src/library/rsform-api.test.ts +30 -2
  28. package/src/library/rsform-api.ts +2 -1
  29. package/src/rslang/error.ts +7 -2
  30. package/src/rslang/parser/parser.test.ts +2 -1
  31. package/src/rslang/semantic/analyzer.test.ts +56 -6
  32. package/src/rslang/semantic/analyzer.ts +5 -2
  33. package/src/rslang/semantic/type-auditor.test.ts +21 -9
  34. package/src/rslang/semantic/type-auditor.ts +72 -15
@@ -673,18 +673,21 @@ export class TypeAuditor {
673
673
  }
674
674
 
675
675
  private visitProjectSet(node: AstNode): ExpressionType | null {
676
- const argument = this.childTypeDebool(node, 0, RSErrorCode.invalidProjectionSet);
677
- if (argument === null) {
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 (argument.typeID === TypeID.anyTypification) {
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.invalidProjectionSet, node.children[0], [
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.invalidProjectionSet, node.children[0], [
696
- labelRSLangNode(node),
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.invalidProjectionTuple, node.children[0], [
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.invalidProjectionTuple, node.children[0], [
731
- labelRSLangNode(node),
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 {
@@ -1067,6 +1073,50 @@ interface LocalData {
1067
1073
  type: Typification;
1068
1074
  }
1069
1075
 
1076
+ function isLogicBinaryNode(typeID: number): boolean {
1077
+ return (
1078
+ typeID === TokenID.LOGIC_AND ||
1079
+ typeID === TokenID.LOGIC_OR ||
1080
+ typeID === TokenID.LOGIC_IMPLICATION ||
1081
+ typeID === TokenID.LOGIC_EQUIVALENT
1082
+ );
1083
+ }
1084
+
1085
+ function isQuantifierNode(typeID: number): boolean {
1086
+ return typeID === TokenID.QUANTOR_UNIVERSAL || typeID === TokenID.QUANTOR_EXISTS;
1087
+ }
1088
+
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)) {
1094
+ return true;
1095
+ }
1096
+ if (current === stopAt) {
1097
+ return false;
1098
+ }
1099
+ current = current.parent;
1100
+ }
1101
+ return false;
1102
+ }
1103
+
1104
+ /** Right operand subtree of the innermost logic binary containing `node`. */
1105
+ function findRightLogicOperandRoot(node: AstNode): AstNode | null {
1106
+ let current: AstNode | null = node;
1107
+ while (current !== null && current.parent !== null) {
1108
+ const parent: AstNode = current.parent;
1109
+ if (isLogicBinaryNode(parent.typeID)) {
1110
+ const childIndex = parent.children.indexOf(current);
1111
+ if (childIndex > 0) {
1112
+ return current;
1113
+ }
1114
+ }
1115
+ current = parent;
1116
+ }
1117
+ return null;
1118
+ }
1119
+
1070
1120
  /** Local variables context. */
1071
1121
  class LocalContext {
1072
1122
  private onError: (code: RSErrorCode, node: AstNode, params: string[]) => null;
@@ -1124,6 +1174,13 @@ class LocalContext {
1124
1174
  this.onError(RSErrorCode.localUndeclared, node, [alias]);
1125
1175
  return null;
1126
1176
  } else if (local.level < 1) {
1177
+ const subexprRoot = findRightLogicOperandRoot(node);
1178
+ if (subexprRoot !== null) {
1179
+ if (pathContainsQuantifier(node, subexprRoot)) {
1180
+ return this.onError(RSErrorCode.localUndeclaredInSubexpr, node, [alias, labelType(local.type)]);
1181
+ }
1182
+ return this.onError(RSErrorCode.localOutOfScopeParentheses, node, [alias]);
1183
+ }
1127
1184
  this.onError(RSErrorCode.localOutOfScope, node, [alias]);
1128
1185
  return null;
1129
1186
  } else {