@rsconcept/domain 1.0.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 (224) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +55 -0
  3. package/dist/cctext/index.d.ts +1 -0
  4. package/dist/cctext/index.js +42 -0
  5. package/dist/cctext/index.js.map +1 -0
  6. package/dist/cctext/language-api.d.ts +43 -0
  7. package/dist/cctext/language-api.js +252 -0
  8. package/dist/cctext/language-api.js.map +1 -0
  9. package/dist/cctext/language.d.ts +58 -0
  10. package/dist/cctext/language.js +44 -0
  11. package/dist/cctext/language.js.map +1 -0
  12. package/dist/graph/graph.d.ts +62 -0
  13. package/dist/graph/graph.js +385 -0
  14. package/dist/graph/graph.js.map +1 -0
  15. package/dist/graph/index.d.ts +1 -0
  16. package/dist/graph/index.js +384 -0
  17. package/dist/graph/index.js.map +1 -0
  18. package/dist/index.d.ts +28 -0
  19. package/dist/index.js +5851 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/library/folder-tree.d.ts +32 -0
  22. package/dist/library/folder-tree.js +136 -0
  23. package/dist/library/folder-tree.js.map +1 -0
  24. package/dist/library/index.d.ts +17 -0
  25. package/dist/library/index.js +2800 -0
  26. package/dist/library/index.js.map +1 -0
  27. package/dist/library/library-api.d.ts +6 -0
  28. package/dist/library/library-api.js +13 -0
  29. package/dist/library/library-api.js.map +1 -0
  30. package/dist/library/library.d.ts +56 -0
  31. package/dist/library/library.js +23 -0
  32. package/dist/library/library.js.map +1 -0
  33. package/dist/library/oss-api.d.ts +47 -0
  34. package/dist/library/oss-api.js +1105 -0
  35. package/dist/library/oss-api.js.map +1 -0
  36. package/dist/library/oss-layout-api.d.ts +36 -0
  37. package/dist/library/oss-layout-api.js +330 -0
  38. package/dist/library/oss-layout-api.js.map +1 -0
  39. package/dist/library/oss-layout.d.ts +25 -0
  40. package/dist/library/oss-layout.js +1 -0
  41. package/dist/library/oss-layout.js.map +1 -0
  42. package/dist/library/oss.d.ts +136 -0
  43. package/dist/library/oss.js +30 -0
  44. package/dist/library/oss.js.map +1 -0
  45. package/dist/library/rsengine.d.ts +116 -0
  46. package/dist/library/rsengine.js +2604 -0
  47. package/dist/library/rsengine.js.map +1 -0
  48. package/dist/library/rsform-api.d.ts +74 -0
  49. package/dist/library/rsform-api.js +879 -0
  50. package/dist/library/rsform-api.js.map +1 -0
  51. package/dist/library/rsform.d.ts +206 -0
  52. package/dist/library/rsform.js +32 -0
  53. package/dist/library/rsform.js.map +1 -0
  54. package/dist/library/rsmodel-api.d.ts +43 -0
  55. package/dist/library/rsmodel-api.js +836 -0
  56. package/dist/library/rsmodel-api.js.map +1 -0
  57. package/dist/library/rsmodel.d.ts +52 -0
  58. package/dist/library/rsmodel.js +25 -0
  59. package/dist/library/rsmodel.js.map +1 -0
  60. package/dist/library/structure-planner.d.ts +33 -0
  61. package/dist/library/structure-planner.js +481 -0
  62. package/dist/library/structure-planner.js.map +1 -0
  63. package/dist/parsing/ast.d.ts +49 -0
  64. package/dist/parsing/ast.js +93 -0
  65. package/dist/parsing/ast.js.map +1 -0
  66. package/dist/parsing/index.d.ts +3 -0
  67. package/dist/parsing/index.js +141 -0
  68. package/dist/parsing/index.js.map +1 -0
  69. package/dist/parsing/lezer-tree.d.ts +13 -0
  70. package/dist/parsing/lezer-tree.js +50 -0
  71. package/dist/parsing/lezer-tree.js.map +1 -0
  72. package/dist/rslang/api.d.ts +53 -0
  73. package/dist/rslang/api.js +846 -0
  74. package/dist/rslang/api.js.map +1 -0
  75. package/dist/rslang/ast-annotations.d.ts +18 -0
  76. package/dist/rslang/ast-annotations.js +56 -0
  77. package/dist/rslang/ast-annotations.js.map +1 -0
  78. package/dist/rslang/error.d.ts +85 -0
  79. package/dist/rslang/error.js +159 -0
  80. package/dist/rslang/error.js.map +1 -0
  81. package/dist/rslang/eval/calculator.d.ts +43 -0
  82. package/dist/rslang/eval/calculator.js +1639 -0
  83. package/dist/rslang/eval/calculator.js.map +1 -0
  84. package/dist/rslang/eval/evaluation-cache.d.ts +36 -0
  85. package/dist/rslang/eval/evaluation-cache.js +310 -0
  86. package/dist/rslang/eval/evaluation-cache.js.map +1 -0
  87. package/dist/rslang/eval/evaluator.d.ts +70 -0
  88. package/dist/rslang/eval/evaluator.js +1514 -0
  89. package/dist/rslang/eval/evaluator.js.map +1 -0
  90. package/dist/rslang/eval/value-api.d.ts +48 -0
  91. package/dist/rslang/eval/value-api.js +490 -0
  92. package/dist/rslang/eval/value-api.js.map +1 -0
  93. package/dist/rslang/eval/value.d.ts +36 -0
  94. package/dist/rslang/eval/value.js +118 -0
  95. package/dist/rslang/eval/value.js.map +1 -0
  96. package/dist/rslang/index.d.ts +17 -0
  97. package/dist/rslang/index.js +4314 -0
  98. package/dist/rslang/index.js.map +1 -0
  99. package/dist/rslang/labels.d.ts +16 -0
  100. package/dist/rslang/labels.js +315 -0
  101. package/dist/rslang/labels.js.map +1 -0
  102. package/dist/rslang/parser/expression-generator.d.ts +10 -0
  103. package/dist/rslang/parser/expression-generator.js +451 -0
  104. package/dist/rslang/parser/expression-generator.js.map +1 -0
  105. package/dist/rslang/parser/normalize.d.ts +11 -0
  106. package/dist/rslang/parser/normalize.js +507 -0
  107. package/dist/rslang/parser/normalize.js.map +1 -0
  108. package/dist/rslang/parser/parser.d.ts +5 -0
  109. package/dist/rslang/parser/parser.js +24 -0
  110. package/dist/rslang/parser/parser.js.map +1 -0
  111. package/dist/rslang/parser/parser.terms.d.ts +42 -0
  112. package/dist/rslang/parser/parser.terms.js +84 -0
  113. package/dist/rslang/parser/parser.terms.js.map +1 -0
  114. package/dist/rslang/parser/syntax-errors.d.ts +11 -0
  115. package/dist/rslang/parser/syntax-errors.js +403 -0
  116. package/dist/rslang/parser/syntax-errors.js.map +1 -0
  117. package/dist/rslang/parser/token.d.ts +79 -0
  118. package/dist/rslang/parser/token.js +95 -0
  119. package/dist/rslang/parser/token.js.map +1 -0
  120. package/dist/rslang/semantic/analyzer.d.ts +39 -0
  121. package/dist/rslang/semantic/analyzer.js +2604 -0
  122. package/dist/rslang/semantic/analyzer.js.map +1 -0
  123. package/dist/rslang/semantic/arguments-extractor.d.ts +42 -0
  124. package/dist/rslang/semantic/arguments-extractor.js +366 -0
  125. package/dist/rslang/semantic/arguments-extractor.js.map +1 -0
  126. package/dist/rslang/semantic/type-auditor.d.ts +73 -0
  127. package/dist/rslang/semantic/type-auditor.js +1570 -0
  128. package/dist/rslang/semantic/type-auditor.js.map +1 -0
  129. package/dist/rslang/semantic/typification-api.d.ts +27 -0
  130. package/dist/rslang/semantic/typification-api.js +320 -0
  131. package/dist/rslang/semantic/typification-api.js.map +1 -0
  132. package/dist/rslang/semantic/typification-parser.d.ts +12 -0
  133. package/dist/rslang/semantic/typification-parser.js +226 -0
  134. package/dist/rslang/semantic/typification-parser.js.map +1 -0
  135. package/dist/rslang/semantic/typification.d.ts +119 -0
  136. package/dist/rslang/semantic/typification.js +74 -0
  137. package/dist/rslang/semantic/typification.js.map +1 -0
  138. package/dist/rslang/semantic/value-auditor.d.ts +43 -0
  139. package/dist/rslang/semantic/value-auditor.js +523 -0
  140. package/dist/rslang/semantic/value-auditor.js.map +1 -0
  141. package/dist/rslang/semantic/value-class.d.ts +10 -0
  142. package/dist/rslang/semantic/value-class.js +9 -0
  143. package/dist/rslang/semantic/value-class.js.map +1 -0
  144. package/dist/rslang/typification-graph.d.ts +33 -0
  145. package/dist/rslang/typification-graph.js +311 -0
  146. package/dist/rslang/typification-graph.js.map +1 -0
  147. package/dist/shared/branded.d.ts +7 -0
  148. package/dist/shared/branded.js +1 -0
  149. package/dist/shared/branded.js.map +1 -0
  150. package/dist/shared/hash.d.ts +6 -0
  151. package/dist/shared/hash.js +18 -0
  152. package/dist/shared/hash.js.map +1 -0
  153. package/dist/shared/index.d.ts +2 -0
  154. package/dist/shared/index.js +18 -0
  155. package/dist/shared/index.js.map +1 -0
  156. package/package.json +184 -0
  157. package/src/cctext/index.ts +9 -0
  158. package/src/cctext/language-api.test.ts +149 -0
  159. package/src/cctext/language-api.ts +285 -0
  160. package/src/cctext/language.ts +80 -0
  161. package/src/graph/graph.test.ts +392 -0
  162. package/src/graph/graph.ts +433 -0
  163. package/src/graph/index.ts +1 -0
  164. package/src/index.ts +96 -0
  165. package/src/library/folder-tree.test.ts +47 -0
  166. package/src/library/folder-tree.ts +156 -0
  167. package/src/library/index.ts +46 -0
  168. package/src/library/library-api.test.ts +32 -0
  169. package/src/library/library-api.ts +11 -0
  170. package/src/library/library.ts +61 -0
  171. package/src/library/oss-api.ts +449 -0
  172. package/src/library/oss-layout-api.ts +377 -0
  173. package/src/library/oss-layout.ts +27 -0
  174. package/src/library/oss.ts +150 -0
  175. package/src/library/rsengine.ts +593 -0
  176. package/src/library/rsform-api.ts +533 -0
  177. package/src/library/rsform.ts +228 -0
  178. package/src/library/rsmodel-api.ts +340 -0
  179. package/src/library/rsmodel.ts +50 -0
  180. package/src/library/structure-planner.ts +143 -0
  181. package/src/parsing/ast.ts +136 -0
  182. package/src/parsing/index.ts +15 -0
  183. package/src/parsing/lezer-tree.ts +69 -0
  184. package/src/rslang/api.test.ts +116 -0
  185. package/src/rslang/api.ts +183 -0
  186. package/src/rslang/ast-annotations.ts +70 -0
  187. package/src/rslang/error.ts +129 -0
  188. package/src/rslang/eval/calculator.test.ts +124 -0
  189. package/src/rslang/eval/calculator.ts +121 -0
  190. package/src/rslang/eval/evaluation-cache.ts +257 -0
  191. package/src/rslang/eval/evaluator.test.ts +352 -0
  192. package/src/rslang/eval/evaluator.ts +935 -0
  193. package/src/rslang/eval/value-api.test.ts +105 -0
  194. package/src/rslang/eval/value-api.ts +444 -0
  195. package/src/rslang/eval/value.ts +102 -0
  196. package/src/rslang/index.ts +23 -0
  197. package/src/rslang/labels.ts +191 -0
  198. package/src/rslang/parser/expression-generator.test.ts +100 -0
  199. package/src/rslang/parser/expression-generator.ts +466 -0
  200. package/src/rslang/parser/normalize.test.ts +99 -0
  201. package/src/rslang/parser/normalize.ts +462 -0
  202. package/src/rslang/parser/parser.terms.ts +42 -0
  203. package/src/rslang/parser/parser.test.ts +153 -0
  204. package/src/rslang/parser/parser.ts +20 -0
  205. package/src/rslang/parser/rslang.grammar +251 -0
  206. package/src/rslang/parser/syntax-errors.ts +209 -0
  207. package/src/rslang/parser/token.ts +106 -0
  208. package/src/rslang/semantic/analyzer.test.ts +59 -0
  209. package/src/rslang/semantic/analyzer.ts +179 -0
  210. package/src/rslang/semantic/arguments-extractor.ts +327 -0
  211. package/src/rslang/semantic/type-auditor.test.ts +326 -0
  212. package/src/rslang/semantic/type-auditor.ts +1049 -0
  213. package/src/rslang/semantic/typification-api.test.ts +46 -0
  214. package/src/rslang/semantic/typification-api.ts +321 -0
  215. package/src/rslang/semantic/typification-parser.test.ts +50 -0
  216. package/src/rslang/semantic/typification-parser.ts +220 -0
  217. package/src/rslang/semantic/typification.ts +180 -0
  218. package/src/rslang/semantic/value-auditor.test.ts +206 -0
  219. package/src/rslang/semantic/value-auditor.ts +332 -0
  220. package/src/rslang/semantic/value-class.ts +11 -0
  221. package/src/rslang/typification-graph.ts +155 -0
  222. package/src/shared/branded.ts +6 -0
  223. package/src/shared/hash.ts +17 -0
  224. package/src/shared/index.ts +2 -0
@@ -0,0 +1,179 @@
1
+ import { type AstNode, buildTree } from '../../parsing';
2
+ import { annotateError } from '../ast-annotations';
3
+ import { RSErrorCode, type RSErrorDescription } from '../error';
4
+ import { normalizeAST } from '../parser/normalize';
5
+ import { parser as rslangParser } from '../parser/parser';
6
+ import { extractSyntaxErrors } from '../parser/syntax-errors';
7
+ import { TokenID } from '../parser/token';
8
+
9
+ import { TypeAuditor } from './type-auditor';
10
+ import {
11
+ basic,
12
+ bool,
13
+ constant,
14
+ debool,
15
+ type ExpressionType,
16
+ type TypeClass,
17
+ type TypeContext,
18
+ TypeID
19
+ } from './typification';
20
+ import { getTypeClass } from './typification-api';
21
+ import { ValueAuditor } from './value-auditor';
22
+ import { ValueClass, type ValueClassContext } from './value-class';
23
+
24
+ export interface AnalysisBase {
25
+ success: boolean;
26
+ type: ExpressionType | null;
27
+ valueClass: ValueClass | null;
28
+ }
29
+
30
+ export interface AnalysisFast extends AnalysisBase {
31
+ ast: AstNode | null;
32
+ }
33
+
34
+ export interface AnalysisFull extends AnalysisBase {
35
+ ast: AstNode | null;
36
+ errors: RSErrorDescription[];
37
+ }
38
+
39
+ export interface AnalysisOptions {
40
+ expected?: TypeClass;
41
+ isDomain?: boolean;
42
+ annotateTypes?: boolean;
43
+ annotateErrors?: boolean;
44
+ }
45
+
46
+ export class RSLangAnalyzer {
47
+ private typeContext: TypeContext = new Map<string, ExpressionType>();
48
+ private valueContext: ValueClassContext = new Map<string, ValueClass>();
49
+ private typeAuditor: TypeAuditor = new TypeAuditor(this.typeContext);
50
+ private valueAuditor: ValueAuditor = new ValueAuditor(this.valueContext);
51
+
52
+ public addBase(alias: string, isNumeric: boolean = false, valueClass: ValueClass = ValueClass.VALUE): void {
53
+ if (isNumeric) {
54
+ this.typeContext.set(alias, bool(constant(alias)));
55
+ this.valueContext.set(alias, valueClass);
56
+ } else {
57
+ this.typeContext.set(alias, bool(basic(alias)));
58
+ this.valueContext.set(alias, valueClass);
59
+ }
60
+ }
61
+
62
+ public setGlobal(alias: string, type: ExpressionType | null, value: ValueClass | null): void {
63
+ if (type) {
64
+ this.typeContext.set(alias, type);
65
+ }
66
+ if (value) {
67
+ this.valueContext.set(alias, value);
68
+ }
69
+ }
70
+
71
+ public getType(alias: string): ExpressionType | null {
72
+ return this.typeContext.get(alias) ?? null;
73
+ }
74
+
75
+ public checkFast(expression: string, options?: AnalysisOptions): AnalysisFast {
76
+ if (expression.length === 0) {
77
+ return { success: false, type: null, valueClass: null, ast: null };
78
+ }
79
+ const ast = this.parse(expression);
80
+ if (ast.hasError) {
81
+ return { success: false, type: null, valueClass: null, ast: ast };
82
+ }
83
+ const type = this.typeAuditor.run(ast, options?.annotateTypes ?? false);
84
+ if (type === null) {
85
+ return { success: false, type: null, valueClass: null, ast: ast };
86
+ }
87
+
88
+ if (options?.isDomain) {
89
+ if (!isStructureDomain(ast) || type.typeID !== TypeID.collection) {
90
+ return { success: false, type: null, valueClass: null, ast: ast };
91
+ }
92
+ return { success: true, type: debool(type), valueClass: ValueClass.VALUE, ast: ast };
93
+ }
94
+ if (options?.expected && getTypeClass(type.typeID) !== options.expected) {
95
+ return { success: false, type: null, valueClass: null, ast: ast };
96
+ }
97
+
98
+ return {
99
+ success: true,
100
+ type: type,
101
+ valueClass: options?.isDomain ? ValueClass.VALUE : this.valueAuditor.run(ast),
102
+ ast: ast
103
+ };
104
+ }
105
+
106
+ public checkFull(expression: string, options?: AnalysisOptions): AnalysisFull {
107
+ const errors: RSErrorDescription[] = [];
108
+ const reporter = (error: RSErrorDescription) => {
109
+ errors.push(error);
110
+ };
111
+ if (expression.length === 0) {
112
+ reporter({ code: RSErrorCode.cstEmptyDerived, from: 0, to: 0 });
113
+ return { success: false, type: null, valueClass: null, errors: errors, ast: null };
114
+ }
115
+ const ast = this.parse(expression);
116
+ if (ast.hasError) {
117
+ extractSyntaxErrors(ast, expression, reporter, options?.annotateErrors ?? false);
118
+ return { success: false, type: null, valueClass: null, errors, ast };
119
+ }
120
+
121
+ const type = this.typeAuditor.run(ast, options?.annotateTypes ?? false, reporter, options?.annotateErrors ?? false);
122
+ if (type === null) {
123
+ return { success: false, type: null, valueClass: null, errors, ast };
124
+ }
125
+
126
+ if (options?.isDomain) {
127
+ if (!isStructureDomain(ast) || type.typeID !== TypeID.collection) {
128
+ reporter({ code: RSErrorCode.globalStructure, from: ast.from, to: ast.to });
129
+ if (options?.annotateErrors) {
130
+ annotateError(ast, RSErrorCode.globalStructure);
131
+ }
132
+ return { success: false, type: null, valueClass: null, errors, ast };
133
+ }
134
+ return { success: true, type: debool(type), valueClass: ValueClass.VALUE, errors, ast };
135
+ }
136
+ if (options?.expected && getTypeClass(type.typeID) !== options.expected) {
137
+ reporter({
138
+ code: RSErrorCode.expectedType,
139
+ from: ast.from,
140
+ to: ast.to
141
+ });
142
+ if (options?.annotateErrors) {
143
+ annotateError(ast, RSErrorCode.expectedType);
144
+ }
145
+ return { success: false, type: null, valueClass: null, errors, ast };
146
+ }
147
+ const valueClass = options?.isDomain
148
+ ? ValueClass.VALUE
149
+ : this.valueAuditor.run(ast, reporter, options?.annotateErrors ?? false);
150
+ return { success: true, type, valueClass, errors, ast };
151
+ }
152
+
153
+ private parse(expression: string): AstNode {
154
+ const tree = rslangParser.parse(expression);
155
+ const ast = buildTree(tree.cursor());
156
+ normalizeAST(ast, expression);
157
+ return ast;
158
+ }
159
+ }
160
+
161
+ // ======= Internals ========
162
+ function isStructureDomain(node: AstNode): boolean {
163
+ switch (node.typeID) {
164
+ case TokenID.LIT_WHOLE_NUMBERS:
165
+ case TokenID.ID_GLOBAL:
166
+ case TokenID.BOOLEAN:
167
+ case TokenID.DECART:
168
+ case TokenID.NT_ENUMERATION:
169
+ break;
170
+ default:
171
+ return false;
172
+ }
173
+ for (const child of node.children) {
174
+ if (!isStructureDomain(child)) {
175
+ return false;
176
+ }
177
+ }
178
+ return true;
179
+ }
@@ -0,0 +1,327 @@
1
+ /**
2
+ * Module: Type auditor for AST type checking.
3
+ */
4
+
5
+ import { type AstNode, getNodeText } from '../../parsing';
6
+ import { readTypeAnnotation } from '../ast-annotations';
7
+ import { TokenID } from '../parser/token';
8
+
9
+ import { type ExpressionType } from './typification';
10
+
11
+ /** Represents function argument definition. */
12
+ export interface ArgumentsType {
13
+ alias: string;
14
+ type: ExpressionType | null;
15
+ }
16
+
17
+ /** Type auditor for AST type checking.
18
+ * Warning! Assumes that the AST is well-formed and annotated with types.
19
+ */
20
+ export class ArgumentsExtractor {
21
+ private locals: LocalContext = new LocalContext();
22
+ private result: ArgumentsType[] = [];
23
+
24
+ public run(ast: AstNode): ArgumentsType[] {
25
+ if (ast.hasError) {
26
+ return [];
27
+ }
28
+ this.result = [];
29
+ this.locals.clear();
30
+ this.dispatchVisit(ast);
31
+ return this.result;
32
+ }
33
+
34
+ private dispatchDeclare(node: AstNode): boolean {
35
+ return this.processDeclare(node);
36
+ }
37
+
38
+ private processDeclare(node: AstNode): boolean {
39
+ switch (node.typeID) {
40
+ case TokenID.ID_LOCAL:
41
+ return this.declareLocal(node);
42
+ case TokenID.NT_TUPLE_DECL:
43
+ return this.declareTuple(node);
44
+ case TokenID.NT_ENUM_DECL:
45
+ return this.declareEnumeration(node);
46
+ }
47
+ return false;
48
+ }
49
+
50
+ private declareLocal(node: AstNode): boolean {
51
+ this.locals.pushLocal(node);
52
+ return true;
53
+ }
54
+
55
+ private declareTuple(node: AstNode): boolean {
56
+ for (let child = 0; child < node.children.length; child++) {
57
+ if (!this.visitChildDeclaration(node, child)) {
58
+ return false;
59
+ }
60
+ }
61
+ return true;
62
+ }
63
+
64
+ private declareEnumeration(node: AstNode): boolean {
65
+ for (const child of node.children) {
66
+ if (!this.dispatchDeclare(child)) {
67
+ return false;
68
+ }
69
+ }
70
+ return true;
71
+ }
72
+
73
+ private dispatchVisit(node: AstNode): boolean {
74
+ return this.processVisit(node);
75
+ }
76
+
77
+ private processVisit(node: AstNode): boolean {
78
+ switch (node.typeID) {
79
+ case TokenID.ID_GLOBAL:
80
+ case TokenID.ID_FUNCTION:
81
+ case TokenID.ID_PREDICATE:
82
+ case TokenID.ID_RADICAL:
83
+ case TokenID.LIT_INTEGER:
84
+ case TokenID.LIT_WHOLE_NUMBERS:
85
+ case TokenID.LIT_EMPTYSET:
86
+ return true;
87
+
88
+ case TokenID.CARD:
89
+ case TokenID.FILTER:
90
+ case TokenID.PLUS:
91
+ case TokenID.MINUS:
92
+ case TokenID.MULTIPLY:
93
+ case TokenID.LOGIC_AND:
94
+ case TokenID.LOGIC_OR:
95
+ case TokenID.LOGIC_IMPLICATION:
96
+ case TokenID.LOGIC_EQUIVALENT:
97
+ case TokenID.EQUAL:
98
+ case TokenID.NOTEQUAL:
99
+ case TokenID.GREATER:
100
+ case TokenID.LESSER:
101
+ case TokenID.GREATER_OR_EQ:
102
+ case TokenID.LESSER_OR_EQ:
103
+ case TokenID.SET_IN:
104
+ case TokenID.SET_NOT_IN:
105
+ case TokenID.SUBSET:
106
+ case TokenID.SUBSET_OR_EQ:
107
+ case TokenID.NOT_SUBSET:
108
+ case TokenID.DECART:
109
+ case TokenID.BOOLEAN:
110
+ case TokenID.BIGPR:
111
+ case TokenID.SMALLPR:
112
+ case TokenID.REDUCE:
113
+ case TokenID.BOOL:
114
+ case TokenID.DEBOOL:
115
+ case TokenID.SET_UNION:
116
+ case TokenID.SET_INTERSECTION:
117
+ case TokenID.SET_MINUS:
118
+ case TokenID.SET_SYMMETRIC_MINUS:
119
+ case TokenID.LOGIC_NOT:
120
+ case TokenID.NT_TUPLE:
121
+ case TokenID.NT_ENUMERATION:
122
+ case TokenID.NT_ARGUMENTS:
123
+ return this.visitAllAndReturn(node);
124
+
125
+ case TokenID.ID_LOCAL:
126
+ return this.visitLocal(node);
127
+
128
+ case TokenID.NT_ARG_DECL:
129
+ return this.visitArgument(node);
130
+
131
+ case TokenID.QUANTOR_UNIVERSAL:
132
+ case TokenID.QUANTOR_EXISTS:
133
+ case TokenID.NT_DECLARATIVE_EXPR:
134
+ return this.visitQuantifier(node);
135
+
136
+ case TokenID.NT_FUNC_DEFINITION:
137
+ return this.visitFunctionDefinition(node);
138
+
139
+ case TokenID.NT_FUNC_CALL:
140
+ return this.visitFunctionCall(node);
141
+
142
+ case TokenID.ITERATE:
143
+ case TokenID.ASSIGN:
144
+ return this.visitIterate(node);
145
+
146
+ case TokenID.NT_IMPERATIVE_EXPR:
147
+ return this.visitImperative(node);
148
+
149
+ case TokenID.NT_RECURSIVE_FULL:
150
+ case TokenID.NT_RECURSIVE_SHORT:
151
+ return this.visitRecursion(node);
152
+ }
153
+ return false;
154
+ }
155
+
156
+ private visitChild(node: AstNode, index: number): boolean {
157
+ return index < node.children.length && this.dispatchVisit(node.children[index]);
158
+ }
159
+
160
+ private visitChildDeclaration(node: AstNode, index: number): boolean {
161
+ return index < node.children.length && this.dispatchDeclare(node.children[index]);
162
+ }
163
+
164
+ private visitAllAndReturn(node: AstNode): boolean {
165
+ for (const child of node.children) {
166
+ if (!this.dispatchVisit(child)) {
167
+ return false;
168
+ }
169
+ }
170
+ return true;
171
+ }
172
+
173
+ private visitLocal(node: AstNode): boolean {
174
+ const alias = getNodeText(node);
175
+ if (!this.locals.checkLocal(node) && this.result.find(arg => arg.alias === alias) === undefined) {
176
+ this.result.push({ alias, type: readTypeAnnotation(node) });
177
+ }
178
+ return true;
179
+ }
180
+
181
+ private visitFunctionDefinition(node: AstNode): boolean {
182
+ this.locals.startScope();
183
+ if (!this.visitChild(node, 0)) {
184
+ return false;
185
+ }
186
+ if (!this.visitChild(node, 1)) {
187
+ return false;
188
+ }
189
+ this.locals.endScope();
190
+ return true;
191
+ }
192
+
193
+ private visitFunctionCall(node: AstNode): boolean {
194
+ for (let child = 1; child < node.children.length; child++) {
195
+ if (!this.visitChild(node, child)) {
196
+ return false;
197
+ }
198
+ }
199
+ return true;
200
+ }
201
+
202
+ private visitArgument(node: AstNode): boolean {
203
+ return this.visitChild(node, 1) && this.visitChildDeclaration(node, 0);
204
+ }
205
+
206
+ private visitQuantifier(node: AstNode): boolean {
207
+ this.locals.startScope();
208
+
209
+ if (!this.visitChild(node, 1)) {
210
+ return false;
211
+ }
212
+ if (!this.visitChildDeclaration(node, 0)) {
213
+ return false;
214
+ }
215
+ if (!this.visitChild(node, 2)) {
216
+ return false;
217
+ }
218
+
219
+ this.locals.endScope();
220
+ return true;
221
+ }
222
+
223
+ private visitImperative(node: AstNode): boolean {
224
+ this.locals.startScope();
225
+
226
+ for (let child = 1; child < node.children.length; child++) {
227
+ if (!this.visitChild(node, child)) {
228
+ return false;
229
+ }
230
+ }
231
+
232
+ if (!this.visitChild(node, 0)) {
233
+ return false;
234
+ }
235
+
236
+ this.locals.endScope();
237
+ return true;
238
+ }
239
+
240
+ private visitIterate(node: AstNode): boolean {
241
+ return this.visitChild(node, 1) && this.visitChildDeclaration(node, 0);
242
+ }
243
+
244
+ private visitRecursion(node: AstNode): boolean {
245
+ this.locals.startScope();
246
+
247
+ if (!this.visitChild(node, 1)) {
248
+ return false;
249
+ }
250
+ if (!this.visitChildDeclaration(node, 0)) {
251
+ return false;
252
+ }
253
+
254
+ const isFull = node.typeID === TokenID.NT_RECURSIVE_FULL;
255
+ const iterationIndex = isFull ? 3 : 2;
256
+
257
+ if (!this.visitChild(node, iterationIndex)) {
258
+ return false;
259
+ }
260
+
261
+ if (isFull) {
262
+ if (!this.visitChild(node, 2)) {
263
+ return false;
264
+ }
265
+ }
266
+
267
+ this.locals.endScope();
268
+ return true;
269
+ }
270
+ }
271
+
272
+ // ========= Internals ========
273
+
274
+ /** Local variable data. */
275
+ interface LocalData {
276
+ alias: string;
277
+ level: number;
278
+ }
279
+
280
+ /** Local variables context. */
281
+ class LocalContext {
282
+ public data: LocalData[] = [];
283
+
284
+ clear(): void {
285
+ this.data = [];
286
+ }
287
+
288
+ startScope(): void {
289
+ for (const local of this.data) {
290
+ if (local.level > 0) {
291
+ local.level = local.level + 1;
292
+ }
293
+ }
294
+ }
295
+
296
+ endScope(): void {
297
+ for (const local of this.data) {
298
+ local.level--;
299
+ }
300
+ }
301
+
302
+ clearUnused(): void {
303
+ this.data = this.data.filter(data => data.level > 0);
304
+ }
305
+
306
+ pushLocal(node: AstNode) {
307
+ const alias = getNodeText(node);
308
+ const existing = this.data.find(data => data.alias === alias);
309
+ if (existing) {
310
+ if (existing.level > 0) {
311
+ return;
312
+ } else {
313
+ const index = this.data.indexOf(existing);
314
+ if (index !== -1) {
315
+ this.data.splice(index, 1);
316
+ }
317
+ }
318
+ }
319
+ this.data.push({ alias, level: 1 });
320
+ }
321
+
322
+ checkLocal(node: AstNode): boolean {
323
+ const alias = getNodeText(node);
324
+ const local = this.data.find(data => data.alias === alias);
325
+ return local !== undefined;
326
+ }
327
+ }