@rsconcept/domain 1.6.1 → 1.7.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-camCAEkQ.d.ts → analyzer-CqUJ3FO9.d.ts} +2 -2
- package/dist/{ast-annotations-DiXmFraa.d.ts → ast-annotations-DvB1VcUv.d.ts} +2 -2
- package/dist/{calculator-BuVooqpb.d.ts → calculator-DKxDpTdT.d.ts} +2 -2
- package/dist/{error-CZXO5Y6a.d.ts → error-CLnXbkly.d.ts} +5 -1
- 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.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 +4 -0
- 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 +213 -1
- package/dist/rslang/parser/syntax-errors.js.map +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/package.json +1 -1
- package/src/rslang/error.ts +4 -0
- package/src/rslang/parser/parser.test.ts +39 -6
- package/src/rslang/parser/syntax-errors.ts +422 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as AstNode } from "./ast-C8sIpKdL.js";
|
|
2
2
|
import { f as ExpressionType, g as TypeClass } from "./typification-Dk-fisgO.js";
|
|
3
|
-
import { i as RSErrorDescription } from "./error-
|
|
3
|
+
import { i as RSErrorDescription } from "./error-CLnXbkly.js";
|
|
4
4
|
import { t as ValueClass } from "./value-class-CNI-lqXJ.js";
|
|
5
5
|
|
|
6
6
|
//#region src/rslang/semantic/analyzer.d.ts
|
|
@@ -36,4 +36,4 @@ declare class RSLangAnalyzer {
|
|
|
36
36
|
}
|
|
37
37
|
//#endregion
|
|
38
38
|
export { RSLangAnalyzer as a, AnalysisOptions as i, AnalysisFast as n, AnalysisFull as r, AnalysisBase as t };
|
|
39
|
-
//# sourceMappingURL=analyzer-
|
|
39
|
+
//# sourceMappingURL=analyzer-CqUJ3FO9.d.ts.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as AstNode } from "./ast-C8sIpKdL.js";
|
|
2
2
|
import { f as ExpressionType } from "./typification-Dk-fisgO.js";
|
|
3
|
-
import { a as RSErrorInfo, r as RSErrorCode } from "./error-
|
|
3
|
+
import { a as RSErrorInfo, r as RSErrorCode } from "./error-CLnXbkly.js";
|
|
4
4
|
|
|
5
5
|
//#region src/rslang/ast-annotations.d.ts
|
|
6
6
|
/** Appends {@link ExpressionType} onto the node's `annotation.rsType`. */
|
|
@@ -13,4 +13,4 @@ declare function annotateError(node: AstNode, code: RSErrorCode, params?: readon
|
|
|
13
13
|
declare function readErrorAnnotation(node: AstNode): RSErrorInfo | null;
|
|
14
14
|
//#endregion
|
|
15
15
|
export { readTypeAnnotation as i, annotateType as n, readErrorAnnotation as r, annotateError as t };
|
|
16
|
-
//# sourceMappingURL=ast-annotations-
|
|
16
|
+
//# sourceMappingURL=ast-annotations-DvB1VcUv.d.ts.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as AstNode } from "./ast-C8sIpKdL.js";
|
|
2
2
|
import { f as ExpressionType } from "./typification-Dk-fisgO.js";
|
|
3
|
-
import { i as RSErrorDescription } from "./error-
|
|
3
|
+
import { i as RSErrorDescription } from "./error-CLnXbkly.js";
|
|
4
4
|
import { l as Value } from "./value-BduA_ZGp.js";
|
|
5
5
|
|
|
6
6
|
//#region src/rslang/eval/calculator.d.ts
|
|
@@ -36,4 +36,4 @@ declare class RSCalculator {
|
|
|
36
36
|
}
|
|
37
37
|
//#endregion
|
|
38
38
|
export { CalculatorResult as n, RSCalculator as r, CalculatorEvaluateOptions as t };
|
|
39
|
-
//# sourceMappingURL=calculator-
|
|
39
|
+
//# sourceMappingURL=calculator-DKxDpTdT.d.ts.map
|
|
@@ -33,6 +33,10 @@ declare const RSErrorCode: {
|
|
|
33
33
|
readonly expectedFunctionBody: 33816;
|
|
34
34
|
readonly expectedExpressionBody: 33817;
|
|
35
35
|
readonly expectedLogicBody: 33818;
|
|
36
|
+
readonly expectedQuantifierBody: 33819;
|
|
37
|
+
readonly expectedDeclarativeBody: 33820;
|
|
38
|
+
readonly expectedImperativeBody: 33821;
|
|
39
|
+
readonly expectedRecursiveBody: 33822;
|
|
36
40
|
readonly expectedLocal: 33813;
|
|
37
41
|
readonly expectedType: 33814;
|
|
38
42
|
readonly localDoubleDeclare: 10241;
|
|
@@ -97,4 +101,4 @@ declare function getRSErrorPrefix(code: RSErrorCode): string;
|
|
|
97
101
|
declare function isCritical(code: RSErrorCode): boolean;
|
|
98
102
|
//#endregion
|
|
99
103
|
export { RSErrorInfo as a, RSErrorDescription as i, RSErrorClass as n, getRSErrorPrefix as o, RSErrorCode as r, isCritical as s, ErrorReporter as t };
|
|
100
|
-
//# sourceMappingURL=error-
|
|
104
|
+
//# sourceMappingURL=error-CLnXbkly.d.ts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -9,15 +9,15 @@ import { a as TOKEN_ERROR, c as flattenAst, d as printAst, f as visitAstDFS, i a
|
|
|
9
9
|
import { t as Branded } from "./branded-ZlzIcxzu.js";
|
|
10
10
|
import { n as generateStub, t as applyHash_fnv1a } from "./hash-Y8I4c6Al.js";
|
|
11
11
|
import { O as makeTypePath, b as Typification, d as EmptySetT, f as ExpressionType, g as TypeClass, m as LogicT, t as AnyTypificationT, v as TypeID, y as TypePath } from "./typification-Dk-fisgO.js";
|
|
12
|
-
import { i as RSErrorDescription, r as RSErrorCode } from "./error-
|
|
13
|
-
import { i as readTypeAnnotation, r as readErrorAnnotation } from "./ast-annotations-
|
|
12
|
+
import { i as RSErrorDescription, r as RSErrorCode } from "./error-CLnXbkly.js";
|
|
13
|
+
import { i as readTypeAnnotation, r as readErrorAnnotation } from "./ast-annotations-DvB1VcUv.js";
|
|
14
14
|
import { d as ValuePath, l as Value, o as TUPLE_ID, p as makeValuePath } from "./value-BduA_ZGp.js";
|
|
15
|
-
import { n as CalculatorResult, r as RSCalculator, t as CalculatorEvaluateOptions } from "./calculator-
|
|
15
|
+
import { n as CalculatorResult, r as RSCalculator, t as CalculatorEvaluateOptions } from "./calculator-DKxDpTdT.js";
|
|
16
16
|
import { d as printValue } from "./value-api-B6T6f4Ia.js";
|
|
17
17
|
import { t as parser } from "./parser-Bwd8LxJ1.js";
|
|
18
18
|
import { t as TokenID } from "./token-DeXAmzwr.js";
|
|
19
19
|
import { t as ValueClass } from "./value-class-CNI-lqXJ.js";
|
|
20
|
-
import { a as RSLangAnalyzer, n as AnalysisFast, r as AnalysisFull, t as AnalysisBase } from "./analyzer-
|
|
20
|
+
import { a as RSLangAnalyzer, n as AnalysisFast, r as AnalysisFull, t as AnalysisBase } from "./analyzer-CqUJ3FO9.js";
|
|
21
21
|
import { n as ArgumentsType } from "./arguments-extractor-1acwjQNc.js";
|
|
22
22
|
import { n as applyAsciiTypeSubstitutions, r as parseTypeText } from "./typification-parser-BBVx1RxP.js";
|
|
23
23
|
import { n as TypificationNodeData, t as TypificationGraph } from "./typification-graph-6HcZ-rKH.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as AstNode } from "../ast-C8sIpKdL.js";
|
|
2
2
|
import { l as Value } from "../value-BduA_ZGp.js";
|
|
3
|
-
import { n as CalculatorResult, r as RSCalculator, t as CalculatorEvaluateOptions } from "../calculator-
|
|
3
|
+
import { n as CalculatorResult, r as RSCalculator, t as CalculatorEvaluateOptions } from "../calculator-DKxDpTdT.js";
|
|
4
4
|
import { CstType, RSForm } from "./rsform.js";
|
|
5
5
|
import { BasicBinding, BasicsContext, EvalStatus, RSModel } from "./rsmodel.js";
|
|
6
6
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { r as LibraryItem } from "../library-CYun28Xz.js";
|
|
2
2
|
import { g as TypeClass, y as TypePath } from "../typification-Dk-fisgO.js";
|
|
3
3
|
import { t as ValueClass } from "../value-class-CNI-lqXJ.js";
|
|
4
|
-
import { r as AnalysisFull } from "../analyzer-
|
|
4
|
+
import { r as AnalysisFull } from "../analyzer-CqUJ3FO9.js";
|
|
5
5
|
import { ArgumentValue, Constituenta, CstClass, CstStatus, CstType, RSForm, RSFormStats } from "./rsform.js";
|
|
6
6
|
|
|
7
7
|
//#region src/library/rsform-api.d.ts
|
package/dist/library/rsform.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as Graph } from "../graph-DR8rL2o3.js";
|
|
2
2
|
import { i as LibraryItemReference, n as CurrentVersion, r as LibraryItem, s as VersionInfo } from "../library-CYun28Xz.js";
|
|
3
3
|
import { f as ExpressionType, y as TypePath } from "../typification-Dk-fisgO.js";
|
|
4
|
-
import { a as RSLangAnalyzer, t as AnalysisBase } from "../analyzer-
|
|
4
|
+
import { a as RSLangAnalyzer, t as AnalysisBase } from "../analyzer-CqUJ3FO9.js";
|
|
5
5
|
//#region src/library/rsform.d.ts
|
|
6
6
|
/** Represents {@link Constituenta} type. */
|
|
7
7
|
declare const CstType: {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as readTypeAnnotation, n as annotateType, r as readErrorAnnotation, t as annotateError } from "../ast-annotations-
|
|
1
|
+
import { i as readTypeAnnotation, n as annotateType, r as readErrorAnnotation, t as annotateError } from "../ast-annotations-DvB1VcUv.js";
|
|
2
2
|
export { annotateError, annotateType, readErrorAnnotation, readTypeAnnotation };
|
package/dist/rslang/error.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as RSErrorInfo, i as RSErrorDescription, n as RSErrorClass, o as getRSErrorPrefix, r as RSErrorCode, s as isCritical, t as ErrorReporter } from "../error-
|
|
1
|
+
import { a as RSErrorInfo, i as RSErrorDescription, n as RSErrorClass, o as getRSErrorPrefix, r as RSErrorCode, s as isCritical, t as ErrorReporter } from "../error-CLnXbkly.js";
|
|
2
2
|
export { ErrorReporter, RSErrorClass, RSErrorCode, RSErrorDescription, RSErrorInfo, getRSErrorPrefix, isCritical };
|
package/dist/rslang/error.js
CHANGED
|
@@ -20,6 +20,10 @@ const RSErrorCode = {
|
|
|
20
20
|
expectedFunctionBody: 33816,
|
|
21
21
|
expectedExpressionBody: 33817,
|
|
22
22
|
expectedLogicBody: 33818,
|
|
23
|
+
expectedQuantifierBody: 33819,
|
|
24
|
+
expectedDeclarativeBody: 33820,
|
|
25
|
+
expectedImperativeBody: 33821,
|
|
26
|
+
expectedRecursiveBody: 33822,
|
|
23
27
|
expectedLocal: 33813,
|
|
24
28
|
expectedType: 33814,
|
|
25
29
|
localDoubleDeclare: 10241,
|
package/dist/rslang/error.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error.js","names":[],"sources":["../../src/rslang/error.ts"],"sourcesContent":["/** Module: Error types and functions. */\n\n/** Represents error class. */\nexport const RSErrorClass = {\n LEXER: 0,\n PARSER: 1,\n SEMANTIC: 2,\n EVALUATION: 3,\n UNKNOWN: 4\n} as const;\nexport type RSErrorClass = (typeof RSErrorClass)[keyof typeof RSErrorClass];\n\n/** Represents RSLang expression error information. */\nexport interface RSErrorInfo {\n code: RSErrorCode;\n params?: readonly string[];\n}\n\n/** Represents RSLang expression error description. */\nexport interface RSErrorDescription extends RSErrorInfo {\n from: number;\n to: number;\n}\n\n/** Error reporter function type. */\nexport type ErrorReporter = (error: RSErrorDescription) => void;\n\n/** Represents RSLang expression error types. */\nexport const RSErrorCode = {\n unknownSyntax: 0x8400, // 33792\n forbiddenCharacter: 0x8401, // 33793\n bracketMismatch: 0x8409, // 33801\n doubleParenthesis: 0x840a, // 33802\n missingOpenBracket: 0x840b, // 33803\n missingCloseBracket: 0x840c, // 33804\n invalidFilterSyntax: 0x8417, // 33815\n expectedFunctionBody: 0x8418, // 33816\n expectedExpressionBody: 0x8419, // 33817\n expectedLogicBody: 0x841a, // 33818\n expectedLocal: 0x8415, // 33813\n expectedType: 0x8416, // 33814\n\n localDoubleDeclare: 0x2801, // 10241\n localNotUsed: 0x2802, // 10242\n\n localUndeclared: 0x8801, // 34817\n localShadowing: 0x8802, // 34818\n\n typesNotEqual: 0x8803, // 34819\n globalNotTyped: 0x8804, // 34820\n invalidDecart: 0x8805, // 34821\n invalidBoolean: 0x8806, // 34822\n invalidTypeOperation: 0x8807, // 34823\n invalidCard: 0x8808, // 34824\n invalidDebool: 0x8809, // 34825\n globalFuncWithoutArgs: 0x880b, // 34827\n invalidReduce: 0x8810, // 34832\n invalidEnumeration: 0x8813, // 34835\n projectionSetArgumentNotSet: 0x8830, // 34864\n projectionSetArgumentNotTupleSet: 0x8831, // 34865\n projectionSetIndexOutOfRange: 0x8832, // 34866\n projectionTupleArgumentNotTuple: 0x8833, // 34867\n projectionTupleIndexOutOfRange: 0x8834, // 34868\n invalidCortegeDeclare: 0x8814, // 34836\n localOutOfScope: 0x8815, // 34837\n invalidElementPredicate: 0x8816, // 34838\n invalidEmptySetUsage: 0x8817, // 34839\n invalidArgsArity: 0x8818, // 34840\n invalidArgumentType: 0x8819, // 34841\n globalStructure: 0x881c, // 34844\n radicalUsage: 0x8821, // 34849\n invalidFilterArgumentType: 0x8822, // 34850\n invalidFilterArity: 0x8823, // 34851\n arithmeticNotSupported: 0x8824, // 34852\n typesNotCompatible: 0x8825, // 34853\n orderingNotSupported: 0x8826, // 34854\n expectedLogic: 0x8827, // 34855\n expectedSetexpr: 0x8828, // 34856\n invalidArgumentCortegeDeclare: 0x8829, // 34857\n invalidQuantifierDomain: 0x882a, // 34858\n invalidFilterParameterType: 0x882b, // 34859\n invalidFilterIndex: 0x882c, // 34860\n invalidFilterBooleanEchelon: 0x882d, // 34861\n localOutOfScopeParentheses: 0x882e, // 34862\n localUndeclaredInSubexpr: 0x882f, // 34863\n\n globalNoValue: 0x8840, // 34880\n invalidPropertyUsage: 0x8841, // 34881\n\n // Value evaluation (runtime)\n calcUnknownError: 0x8100, // 35328\n setOverflow: 0x8101, // 35329\n booleanBaseLimit: 0x8102, // 35330\n calcGlobalMissing: 0x8103, // 35331\n iterationsLimit: 0x8104, // 35332\n calcInvalidDebool: 0x8105, // 35333\n iterateInfinity: 0x8106, // 35334\n calculationNotSupported: 0x8107, // 35335\n calcInvalidData: 0x8108, // 35336\n\n cstEmptyDerived: 0x8861, // 34913\n definitionNotAllowed: 0x8862 // 34914\n} as const;\nexport type RSErrorCode = (typeof RSErrorCode)[keyof typeof RSErrorCode];\n\nconst ERROR_EVALUATION_MASK = 0x0100;\nconst ERROR_LEXER_MASK = 0x0200;\nconst ERROR_PARSER_MASK = 0x0400;\nconst ERROR_SEMANTIC_MASK = 0x0800;\n\n/** Infers error class from error type (code). */\nfunction inferErrorClass(error: RSErrorCode): RSErrorClass {\n if ((error & ERROR_EVALUATION_MASK) !== 0) {\n return RSErrorClass.EVALUATION;\n } else if ((error & ERROR_LEXER_MASK) !== 0) {\n return RSErrorClass.LEXER;\n } else if ((error & ERROR_PARSER_MASK) !== 0) {\n return RSErrorClass.PARSER;\n } else if ((error & ERROR_SEMANTIC_MASK) !== 0) {\n return RSErrorClass.SEMANTIC;\n } else {\n return RSErrorClass.UNKNOWN;\n }\n}\n\n/** Generate ErrorID label. */\nexport function getRSErrorPrefix(code: RSErrorCode): string {\n const id = code.toString(16).toUpperCase();\n // prettier-ignore\n switch (inferErrorClass(code)) {\n case RSErrorClass.LEXER: return 'L' + id;\n case RSErrorClass.PARSER: return 'P' + id;\n case RSErrorClass.SEMANTIC: return 'S' + id;\n case RSErrorClass.EVALUATION: return 'E' + id;\n case RSErrorClass.UNKNOWN: return 'U' + id;\n }\n}\n\n/** Checks if error is critical. */\nexport function isCritical(code: RSErrorCode): boolean {\n return code !== RSErrorCode.localDoubleDeclare && code !== RSErrorCode.localNotUsed;\n}\n"],"mappings":";;;AAGA,MAAa,eAAe;CAC1B,OAAO;CACP,QAAQ;CACR,UAAU;CACV,YAAY;CACZ,SAAS;AACX;;AAmBA,MAAa,cAAc;CACzB,eAAe;CACf,oBAAoB;CACpB,iBAAiB;CACjB,mBAAmB;CACnB,oBAAoB;CACpB,qBAAqB;CACrB,qBAAqB;CACrB,sBAAsB;CACtB,wBAAwB;CACxB,mBAAmB;CACnB,eAAe;CACf,cAAc;CAEd,oBAAoB;CACpB,cAAc;CAEd,iBAAiB;CACjB,gBAAgB;CAEhB,eAAe;CACf,gBAAgB;CAChB,eAAe;CACf,gBAAgB;CAChB,sBAAsB;CACtB,aAAa;CACb,eAAe;CACf,uBAAuB;CACvB,eAAe;CACf,oBAAoB;CACpB,6BAA6B;CAC7B,kCAAkC;CAClC,8BAA8B;CAC9B,iCAAiC;CACjC,gCAAgC;CAChC,uBAAuB;CACvB,iBAAiB;CACjB,yBAAyB;CACzB,sBAAsB;CACtB,kBAAkB;CAClB,qBAAqB;CACrB,iBAAiB;CACjB,cAAc;CACd,2BAA2B;CAC3B,oBAAoB;CACpB,wBAAwB;CACxB,oBAAoB;CACpB,sBAAsB;CACtB,eAAe;CACf,iBAAiB;CACjB,+BAA+B;CAC/B,yBAAyB;CACzB,4BAA4B;CAC5B,oBAAoB;CACpB,6BAA6B;CAC7B,4BAA4B;CAC5B,0BAA0B;CAE1B,eAAe;CACf,sBAAsB;CAGtB,kBAAkB;CAClB,aAAa;CACb,kBAAkB;CAClB,mBAAmB;CACnB,iBAAiB;CACjB,mBAAmB;CACnB,iBAAiB;CACjB,yBAAyB;CACzB,iBAAiB;CAEjB,iBAAiB;CACjB,sBAAsB;AACxB;AAGA,MAAM,wBAAwB;AAC9B,MAAM,mBAAmB;AACzB,MAAM,oBAAoB;AAC1B,MAAM,sBAAsB;;AAG5B,SAAS,gBAAgB,OAAkC;CACzD,KAAK,QAAQ,2BAA2B,GACtC,OAAO,aAAa;MACf,KAAK,QAAQ,sBAAsB,GACxC,OAAO,aAAa;MACf,KAAK,QAAQ,uBAAuB,GACzC,OAAO,aAAa;MACf,KAAK,QAAQ,yBAAyB,GAC3C,OAAO,aAAa;MAEpB,OAAO,aAAa;AAExB;;AAGA,SAAgB,iBAAiB,MAA2B;CAC1D,MAAM,KAAK,KAAK,SAAS,EAAE,CAAC,CAAC,YAAY;CAEzC,QAAQ,gBAAgB,IAAI,GAA5B;EACE,KAAK,aAAa,OAAO,OAAO,MAAM;EACtC,KAAK,aAAa,QAAQ,OAAO,MAAM;EACvC,KAAK,aAAa,UAAU,OAAO,MAAM;EACzC,KAAK,aAAa,YAAY,OAAO,MAAM;EAC3C,KAAK,aAAa,SAAS,OAAO,MAAM;CAC1C;AACF;;AAGA,SAAgB,WAAW,MAA4B;CACrD,OAAO,SAAS,YAAY,sBAAsB,SAAS,YAAY;AACzE"}
|
|
1
|
+
{"version":3,"file":"error.js","names":[],"sources":["../../src/rslang/error.ts"],"sourcesContent":["/** Module: Error types and functions. */\n\n/** Represents error class. */\nexport const RSErrorClass = {\n LEXER: 0,\n PARSER: 1,\n SEMANTIC: 2,\n EVALUATION: 3,\n UNKNOWN: 4\n} as const;\nexport type RSErrorClass = (typeof RSErrorClass)[keyof typeof RSErrorClass];\n\n/** Represents RSLang expression error information. */\nexport interface RSErrorInfo {\n code: RSErrorCode;\n params?: readonly string[];\n}\n\n/** Represents RSLang expression error description. */\nexport interface RSErrorDescription extends RSErrorInfo {\n from: number;\n to: number;\n}\n\n/** Error reporter function type. */\nexport type ErrorReporter = (error: RSErrorDescription) => void;\n\n/** Represents RSLang expression error types. */\nexport const RSErrorCode = {\n unknownSyntax: 0x8400, // 33792\n forbiddenCharacter: 0x8401, // 33793\n bracketMismatch: 0x8409, // 33801\n doubleParenthesis: 0x840a, // 33802\n missingOpenBracket: 0x840b, // 33803\n missingCloseBracket: 0x840c, // 33804\n invalidFilterSyntax: 0x8417, // 33815\n expectedFunctionBody: 0x8418, // 33816\n expectedExpressionBody: 0x8419, // 33817\n expectedLogicBody: 0x841a, // 33818\n expectedQuantifierBody: 0x841b, // 33819\n expectedDeclarativeBody: 0x841c, // 33820\n expectedImperativeBody: 0x841d, // 33821\n expectedRecursiveBody: 0x841e, // 33822\n expectedLocal: 0x8415, // 33813\n expectedType: 0x8416, // 33814\n\n localDoubleDeclare: 0x2801, // 10241\n localNotUsed: 0x2802, // 10242\n\n localUndeclared: 0x8801, // 34817\n localShadowing: 0x8802, // 34818\n\n typesNotEqual: 0x8803, // 34819\n globalNotTyped: 0x8804, // 34820\n invalidDecart: 0x8805, // 34821\n invalidBoolean: 0x8806, // 34822\n invalidTypeOperation: 0x8807, // 34823\n invalidCard: 0x8808, // 34824\n invalidDebool: 0x8809, // 34825\n globalFuncWithoutArgs: 0x880b, // 34827\n invalidReduce: 0x8810, // 34832\n invalidEnumeration: 0x8813, // 34835\n projectionSetArgumentNotSet: 0x8830, // 34864\n projectionSetArgumentNotTupleSet: 0x8831, // 34865\n projectionSetIndexOutOfRange: 0x8832, // 34866\n projectionTupleArgumentNotTuple: 0x8833, // 34867\n projectionTupleIndexOutOfRange: 0x8834, // 34868\n invalidCortegeDeclare: 0x8814, // 34836\n localOutOfScope: 0x8815, // 34837\n invalidElementPredicate: 0x8816, // 34838\n invalidEmptySetUsage: 0x8817, // 34839\n invalidArgsArity: 0x8818, // 34840\n invalidArgumentType: 0x8819, // 34841\n globalStructure: 0x881c, // 34844\n radicalUsage: 0x8821, // 34849\n invalidFilterArgumentType: 0x8822, // 34850\n invalidFilterArity: 0x8823, // 34851\n arithmeticNotSupported: 0x8824, // 34852\n typesNotCompatible: 0x8825, // 34853\n orderingNotSupported: 0x8826, // 34854\n expectedLogic: 0x8827, // 34855\n expectedSetexpr: 0x8828, // 34856\n invalidArgumentCortegeDeclare: 0x8829, // 34857\n invalidQuantifierDomain: 0x882a, // 34858\n invalidFilterParameterType: 0x882b, // 34859\n invalidFilterIndex: 0x882c, // 34860\n invalidFilterBooleanEchelon: 0x882d, // 34861\n localOutOfScopeParentheses: 0x882e, // 34862\n localUndeclaredInSubexpr: 0x882f, // 34863\n\n globalNoValue: 0x8840, // 34880\n invalidPropertyUsage: 0x8841, // 34881\n\n // Value evaluation (runtime)\n calcUnknownError: 0x8100, // 35328\n setOverflow: 0x8101, // 35329\n booleanBaseLimit: 0x8102, // 35330\n calcGlobalMissing: 0x8103, // 35331\n iterationsLimit: 0x8104, // 35332\n calcInvalidDebool: 0x8105, // 35333\n iterateInfinity: 0x8106, // 35334\n calculationNotSupported: 0x8107, // 35335\n calcInvalidData: 0x8108, // 35336\n\n cstEmptyDerived: 0x8861, // 34913\n definitionNotAllowed: 0x8862 // 34914\n} as const;\nexport type RSErrorCode = (typeof RSErrorCode)[keyof typeof RSErrorCode];\n\nconst ERROR_EVALUATION_MASK = 0x0100;\nconst ERROR_LEXER_MASK = 0x0200;\nconst ERROR_PARSER_MASK = 0x0400;\nconst ERROR_SEMANTIC_MASK = 0x0800;\n\n/** Infers error class from error type (code). */\nfunction inferErrorClass(error: RSErrorCode): RSErrorClass {\n if ((error & ERROR_EVALUATION_MASK) !== 0) {\n return RSErrorClass.EVALUATION;\n } else if ((error & ERROR_LEXER_MASK) !== 0) {\n return RSErrorClass.LEXER;\n } else if ((error & ERROR_PARSER_MASK) !== 0) {\n return RSErrorClass.PARSER;\n } else if ((error & ERROR_SEMANTIC_MASK) !== 0) {\n return RSErrorClass.SEMANTIC;\n } else {\n return RSErrorClass.UNKNOWN;\n }\n}\n\n/** Generate ErrorID label. */\nexport function getRSErrorPrefix(code: RSErrorCode): string {\n const id = code.toString(16).toUpperCase();\n // prettier-ignore\n switch (inferErrorClass(code)) {\n case RSErrorClass.LEXER: return 'L' + id;\n case RSErrorClass.PARSER: return 'P' + id;\n case RSErrorClass.SEMANTIC: return 'S' + id;\n case RSErrorClass.EVALUATION: return 'E' + id;\n case RSErrorClass.UNKNOWN: return 'U' + id;\n }\n}\n\n/** Checks if error is critical. */\nexport function isCritical(code: RSErrorCode): boolean {\n return code !== RSErrorCode.localDoubleDeclare && code !== RSErrorCode.localNotUsed;\n}\n"],"mappings":";;;AAGA,MAAa,eAAe;CAC1B,OAAO;CACP,QAAQ;CACR,UAAU;CACV,YAAY;CACZ,SAAS;AACX;;AAmBA,MAAa,cAAc;CACzB,eAAe;CACf,oBAAoB;CACpB,iBAAiB;CACjB,mBAAmB;CACnB,oBAAoB;CACpB,qBAAqB;CACrB,qBAAqB;CACrB,sBAAsB;CACtB,wBAAwB;CACxB,mBAAmB;CACnB,wBAAwB;CACxB,yBAAyB;CACzB,wBAAwB;CACxB,uBAAuB;CACvB,eAAe;CACf,cAAc;CAEd,oBAAoB;CACpB,cAAc;CAEd,iBAAiB;CACjB,gBAAgB;CAEhB,eAAe;CACf,gBAAgB;CAChB,eAAe;CACf,gBAAgB;CAChB,sBAAsB;CACtB,aAAa;CACb,eAAe;CACf,uBAAuB;CACvB,eAAe;CACf,oBAAoB;CACpB,6BAA6B;CAC7B,kCAAkC;CAClC,8BAA8B;CAC9B,iCAAiC;CACjC,gCAAgC;CAChC,uBAAuB;CACvB,iBAAiB;CACjB,yBAAyB;CACzB,sBAAsB;CACtB,kBAAkB;CAClB,qBAAqB;CACrB,iBAAiB;CACjB,cAAc;CACd,2BAA2B;CAC3B,oBAAoB;CACpB,wBAAwB;CACxB,oBAAoB;CACpB,sBAAsB;CACtB,eAAe;CACf,iBAAiB;CACjB,+BAA+B;CAC/B,yBAAyB;CACzB,4BAA4B;CAC5B,oBAAoB;CACpB,6BAA6B;CAC7B,4BAA4B;CAC5B,0BAA0B;CAE1B,eAAe;CACf,sBAAsB;CAGtB,kBAAkB;CAClB,aAAa;CACb,kBAAkB;CAClB,mBAAmB;CACnB,iBAAiB;CACjB,mBAAmB;CACnB,iBAAiB;CACjB,yBAAyB;CACzB,iBAAiB;CAEjB,iBAAiB;CACjB,sBAAsB;AACxB;AAGA,MAAM,wBAAwB;AAC9B,MAAM,mBAAmB;AACzB,MAAM,oBAAoB;AAC1B,MAAM,sBAAsB;;AAG5B,SAAS,gBAAgB,OAAkC;CACzD,KAAK,QAAQ,2BAA2B,GACtC,OAAO,aAAa;MACf,KAAK,QAAQ,sBAAsB,GACxC,OAAO,aAAa;MACf,KAAK,QAAQ,uBAAuB,GACzC,OAAO,aAAa;MACf,KAAK,QAAQ,yBAAyB,GAC3C,OAAO,aAAa;MAEpB,OAAO,aAAa;AAExB;;AAGA,SAAgB,iBAAiB,MAA2B;CAC1D,MAAM,KAAK,KAAK,SAAS,EAAE,CAAC,CAAC,YAAY;CAEzC,QAAQ,gBAAgB,IAAI,GAA5B;EACE,KAAK,aAAa,OAAO,OAAO,MAAM;EACtC,KAAK,aAAa,QAAQ,OAAO,MAAM;EACvC,KAAK,aAAa,UAAU,OAAO,MAAM;EACzC,KAAK,aAAa,YAAY,OAAO,MAAM;EAC3C,KAAK,aAAa,SAAS,OAAO,MAAM;CAC1C;AACF;;AAGA,SAAgB,WAAW,MAA4B;CACrD,OAAO,SAAS,YAAY,sBAAsB,SAAS,YAAY;AACzE"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as CalculatorResult, r as RSCalculator, t as CalculatorEvaluateOptions } from "../../calculator-
|
|
1
|
+
import { n as CalculatorResult, r as RSCalculator, t as CalculatorEvaluateOptions } from "../../calculator-DKxDpTdT.js";
|
|
2
2
|
export { CalculatorEvaluateOptions, CalculatorResult, RSCalculator };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as AstNode } from "../../ast-C8sIpKdL.js";
|
|
2
|
-
import { t as ErrorReporter } from "../../error-
|
|
2
|
+
import { t as ErrorReporter } from "../../error-CLnXbkly.js";
|
|
3
3
|
import { l as Value, u as ValueContext } from "../../value-BduA_ZGp.js";
|
|
4
4
|
|
|
5
5
|
//#region src/rslang/eval/evaluator.d.ts
|
package/dist/rslang/index.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { O as makeTypePath, b as Typification, d as EmptySetT, f as ExpressionType, g as TypeClass, m as LogicT, t as AnyTypificationT, v as TypeID, y as TypePath } from "../typification-Dk-fisgO.js";
|
|
2
|
-
import { i as RSErrorDescription, r as RSErrorCode } from "../error-
|
|
3
|
-
import { i as readTypeAnnotation, r as readErrorAnnotation } from "../ast-annotations-
|
|
2
|
+
import { i as RSErrorDescription, r as RSErrorCode } from "../error-CLnXbkly.js";
|
|
3
|
+
import { i as readTypeAnnotation, r as readErrorAnnotation } from "../ast-annotations-DvB1VcUv.js";
|
|
4
4
|
import { d as ValuePath, l as Value, p as makeValuePath } from "../value-BduA_ZGp.js";
|
|
5
|
-
import { n as CalculatorResult, r as RSCalculator, t as CalculatorEvaluateOptions } from "../calculator-
|
|
5
|
+
import { n as CalculatorResult, r as RSCalculator, t as CalculatorEvaluateOptions } from "../calculator-DKxDpTdT.js";
|
|
6
6
|
import { d as printValue } from "../value-api-B6T6f4Ia.js";
|
|
7
7
|
import { t as parser } from "../parser-Bwd8LxJ1.js";
|
|
8
8
|
import { t as TokenID } from "../token-DeXAmzwr.js";
|
|
9
9
|
import { t as ValueClass } from "../value-class-CNI-lqXJ.js";
|
|
10
|
-
import { a as RSLangAnalyzer, n as AnalysisFast, r as AnalysisFull, t as AnalysisBase } from "../analyzer-
|
|
10
|
+
import { a as RSLangAnalyzer, n as AnalysisFast, r as AnalysisFull, t as AnalysisBase } from "../analyzer-CqUJ3FO9.js";
|
|
11
11
|
import { n as ArgumentsType } from "../arguments-extractor-1acwjQNc.js";
|
|
12
12
|
import { n as applyAsciiTypeSubstitutions, r as parseTypeText } from "../typification-parser-BBVx1RxP.js";
|
|
13
13
|
import { n as TypificationNodeData, t as TypificationGraph } from "../typification-graph-6HcZ-rKH.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as AstNode } from "../../ast-C8sIpKdL.js";
|
|
2
2
|
import { g as TypeClass } from "../../typification-Dk-fisgO.js";
|
|
3
|
-
import { t as ErrorReporter } from "../../error-
|
|
3
|
+
import { t as ErrorReporter } from "../../error-CLnXbkly.js";
|
|
4
4
|
|
|
5
5
|
//#region src/rslang/parser/syntax-errors.d.ts
|
|
6
6
|
/** Options for syntax error extraction. */
|
|
@@ -26,9 +26,10 @@ function extractSyntaxErrors(ast, expression, reporter, annotateErrors = false,
|
|
|
26
26
|
if (target !== void 0) annotationTargets.set(error, target);
|
|
27
27
|
};
|
|
28
28
|
const bracketError = extractBracketErrors(expression);
|
|
29
|
-
if (bracketError !== null) collect(bracketError, ast);
|
|
30
29
|
const hasBracketErrors = bracketError !== null;
|
|
31
30
|
visitAstDFS(ast, (node) => extractInternal(node, expression, collect, hasBracketErrors, options));
|
|
31
|
+
const hasIncompleteGenerator = collected.some((error) => isIncompleteGeneratorBodyCode(error.code));
|
|
32
|
+
if (bracketError !== null && !hasIncompleteGenerator) collect(bracketError, ast);
|
|
32
33
|
for (const error of deduplicateErrors(collected)) {
|
|
33
34
|
reporter(error);
|
|
34
35
|
if (annotateErrors) {
|
|
@@ -63,6 +64,10 @@ function extractInternal(node, expression, collect, ignoreUnknownErrors, options
|
|
|
63
64
|
function classifyParseError(node, expression, options) {
|
|
64
65
|
const incompleteFunctionDecl = detectIncompleteFunctionDecl(node, expression, options?.expected);
|
|
65
66
|
if (incompleteFunctionDecl !== null) return incompleteFunctionDecl;
|
|
67
|
+
const incompleteQuantifier = detectIncompleteQuantifier(node, expression);
|
|
68
|
+
if (incompleteQuantifier !== null) return incompleteQuantifier;
|
|
69
|
+
const incompleteGenerator = detectIncompleteGenerator(node, expression);
|
|
70
|
+
if (incompleteGenerator !== null) return incompleteGenerator;
|
|
66
71
|
const filterParen = detectFilterParenMismatch(node, expression);
|
|
67
72
|
if (filterParen !== null) return filterParen;
|
|
68
73
|
return detectGlobalFuncWithoutArgs(node, expression);
|
|
@@ -89,6 +94,210 @@ function incompleteFormalExpressionCode(expected) {
|
|
|
89
94
|
default: return RSErrorCode.expectedFunctionBody;
|
|
90
95
|
}
|
|
91
96
|
}
|
|
97
|
+
function detectIncompleteQuantifier(node, expression) {
|
|
98
|
+
const quantNode = findAncestor(node, isQuantifierNode);
|
|
99
|
+
if (quantNode === null) return null;
|
|
100
|
+
const bodyChild = quantNode.children[quantNode.children.length - 1];
|
|
101
|
+
if (bodyChild?.typeID !== TokenID.ERROR || node !== bodyChild) return null;
|
|
102
|
+
const headerChildren = quantNode.children.slice(0, -1);
|
|
103
|
+
if (headerChildren.length < 3) return null;
|
|
104
|
+
const varPack = headerChildren.find((child) => child.typeID === 31 || child.typeID === TokenID.NT_ENUM_DECL);
|
|
105
|
+
if (varPack === void 0 || subtreeHasError(varPack)) return null;
|
|
106
|
+
const domainChild = headerChildren[headerChildren.length - 1];
|
|
107
|
+
if (domainChild === varPack || subtreeHasError(domainChild)) return null;
|
|
108
|
+
if (expression.slice(quantNode.to).trim().length > 0) return null;
|
|
109
|
+
return {
|
|
110
|
+
code: RSErrorCode.expectedQuantifierBody,
|
|
111
|
+
from: bodyChild.from,
|
|
112
|
+
to: bodyChild.to
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function detectIncompleteGenerator(node, expression) {
|
|
116
|
+
return detectIncompleteDeclarative(node, expression) ?? detectIncompleteImperative(node, expression) ?? detectIncompleteRecursion(node, expression);
|
|
117
|
+
}
|
|
118
|
+
function detectIncompleteDeclarative(node, expression) {
|
|
119
|
+
return detectIncompleteGeneratorBody(node, expression, findAncestor(node, (target) => target.typeID === 60 || target.typeID === TokenID.NT_DECLARATIVE_EXPR), RSErrorCode.expectedDeclarativeBody, (slot) => isIncompleteDeclarativeBody(slot));
|
|
120
|
+
}
|
|
121
|
+
function detectIncompleteImperative(node, expression) {
|
|
122
|
+
return detectIncompleteGeneratorBody(node, expression, findAncestor(node, (target) => target.typeID === 64 || target.typeID === TokenID.NT_IMPERATIVE_EXPR), RSErrorCode.expectedImperativeBody, (slot) => isIncompleteImperativeBody(slot, expression));
|
|
123
|
+
}
|
|
124
|
+
function detectIncompleteRecursion(node, expression) {
|
|
125
|
+
return detectIncompleteGeneratorBody(node, expression, findAncestor(node, (target) => target.typeID === 68), RSErrorCode.expectedRecursiveBody, (slot) => isIncompleteRecursionBody(slot));
|
|
126
|
+
}
|
|
127
|
+
function detectIncompleteGeneratorBody(node, expression, generatorNode, code, isIncomplete) {
|
|
128
|
+
if (generatorNode === null) return null;
|
|
129
|
+
if (expression.slice(generatorNode.to).trim().length > 0) return null;
|
|
130
|
+
const slot = getGeneratorBodySlot(generatorNode, expression);
|
|
131
|
+
if (slot === null || !isIncomplete(slot)) return null;
|
|
132
|
+
if (!generatorHeaderIsValid(generatorNode, expression, slot.headerEndIndex)) return null;
|
|
133
|
+
if (!isErrorInBodySlot(node, slot, generatorNode)) return null;
|
|
134
|
+
return incompleteGeneratorError(code, node);
|
|
135
|
+
}
|
|
136
|
+
function getGeneratorBodySlot(generatorNode, expression) {
|
|
137
|
+
if (generatorNode.typeID === 60 || generatorNode.typeID === TokenID.NT_DECLARATIVE_EXPR) return getDeclarativeBodySlot(generatorNode, expression);
|
|
138
|
+
if (generatorNode.typeID === 64 || generatorNode.typeID === TokenID.NT_IMPERATIVE_EXPR) return getImperativeBodySlot(generatorNode, expression);
|
|
139
|
+
if (generatorNode.typeID === 68) return getRecursionBodySlot(generatorNode, expression);
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
function getDeclarativeBodySlot(declNode, expression) {
|
|
143
|
+
const pipeIndex = declNode.children.findIndex((child) => isPipeToken(child, expression));
|
|
144
|
+
if (pipeIndex >= 0) return {
|
|
145
|
+
nodes: contentChildren(declNode, expression, pipeIndex + 1),
|
|
146
|
+
headerEndIndex: pipeIndex + 1
|
|
147
|
+
};
|
|
148
|
+
const domainNode = findDeclarativeDomain(declNode, expression);
|
|
149
|
+
if (domainNode === null) return null;
|
|
150
|
+
const domainIndex = declNode.children.indexOf(domainNode);
|
|
151
|
+
return {
|
|
152
|
+
nodes: contentChildren(declNode, expression, domainIndex + 1),
|
|
153
|
+
headerEndIndex: domainIndex + 1
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function getImperativeBodySlot(impNode, expression) {
|
|
157
|
+
const pipeIndex = impNode.children.findIndex((child) => isPipeToken(child, expression));
|
|
158
|
+
if (pipeIndex >= 0) return {
|
|
159
|
+
nodes: contentChildren(impNode, expression, pipeIndex + 1),
|
|
160
|
+
headerEndIndex: pipeIndex + 1
|
|
161
|
+
};
|
|
162
|
+
const tupleNode = findImperativeTuple(impNode);
|
|
163
|
+
if (tupleNode === null) return null;
|
|
164
|
+
const tupleIndex = impNode.children.indexOf(tupleNode);
|
|
165
|
+
return {
|
|
166
|
+
nodes: contentChildren(impNode, expression, tupleIndex + 1),
|
|
167
|
+
headerEndIndex: tupleIndex + 1
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function getRecursionBodySlot(recNode, expression) {
|
|
171
|
+
const initNode = findRecursionInit(recNode, expression);
|
|
172
|
+
if (initNode === null) return null;
|
|
173
|
+
const initIndex = recNode.children.indexOf(initNode);
|
|
174
|
+
const afterInit = contentChildren(recNode, expression, initIndex + 1);
|
|
175
|
+
const lastPipeIndex = findLastPipeIndex(afterInit, expression);
|
|
176
|
+
if (lastPipeIndex < 0) return {
|
|
177
|
+
nodes: afterInit,
|
|
178
|
+
headerEndIndex: initIndex + 1
|
|
179
|
+
};
|
|
180
|
+
return {
|
|
181
|
+
nodes: afterInit.slice(lastPipeIndex + 1),
|
|
182
|
+
headerEndIndex: recNode.children.indexOf(afterInit[lastPipeIndex]) + 1
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
function contentChildren(generatorNode, expression, fromIndex) {
|
|
186
|
+
return generatorNode.children.slice(fromIndex).filter((child) => !isClosingBrace(child, expression));
|
|
187
|
+
}
|
|
188
|
+
function findDeclarativeDomain(declNode, expression) {
|
|
189
|
+
const inIndex = declNode.children.findIndex((child) => expression.slice(child.from, child.to) === "∈");
|
|
190
|
+
if (inIndex < 0) return null;
|
|
191
|
+
for (let index = inIndex + 1; index < declNode.children.length; index++) {
|
|
192
|
+
const child = declNode.children[index];
|
|
193
|
+
if (isPipeToken(child, expression) || isClosingBrace(child, expression)) break;
|
|
194
|
+
if (child.typeID === 38) return child;
|
|
195
|
+
}
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
function findImperativeTuple(impNode) {
|
|
199
|
+
for (const child of impNode.children) if (child.typeID === 38) return child;
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
function findLastPipeIndex(nodes, expression) {
|
|
203
|
+
for (let index = nodes.length - 1; index >= 0; index--) if (isPipeToken(nodes[index], expression)) return index;
|
|
204
|
+
return -1;
|
|
205
|
+
}
|
|
206
|
+
function generatorHeaderIsValid(generatorNode, expression, headerEndIndex) {
|
|
207
|
+
for (let index = 0; index < headerEndIndex; index++) {
|
|
208
|
+
const child = generatorNode.children[index];
|
|
209
|
+
if (child.typeID === TokenID.ERROR) return false;
|
|
210
|
+
if (isStructuralGeneratorToken(child, expression)) continue;
|
|
211
|
+
if (subtreeHasError(child)) return false;
|
|
212
|
+
}
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
function isIncompleteDeclarativeBody(slot) {
|
|
216
|
+
return isEmptyOrErrorOnlyBody(slot.nodes);
|
|
217
|
+
}
|
|
218
|
+
function isIncompleteImperativeBody(slot, expression) {
|
|
219
|
+
if (slot.nodes.length === 0) return true;
|
|
220
|
+
if (slot.nodes.length === 1 && slot.nodes[0].typeID === 65) return isImpBlocksIncomplete(slot.nodes[0], expression);
|
|
221
|
+
return isEmptyOrErrorOnlyBody(slot.nodes);
|
|
222
|
+
}
|
|
223
|
+
function isIncompleteRecursionBody(slot) {
|
|
224
|
+
return isEmptyOrErrorOnlyBody(slot.nodes);
|
|
225
|
+
}
|
|
226
|
+
function isEmptyOrErrorOnlyBody(nodes) {
|
|
227
|
+
if (nodes.length === 0) return true;
|
|
228
|
+
if (nodes.length === 1) return isErrorPlaceholder(nodes[0]);
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
function isImpBlocksIncomplete(blocksNode, expression) {
|
|
232
|
+
if (blocksNode.children.length === 0) return true;
|
|
233
|
+
const lastChild = blocksNode.children[blocksNode.children.length - 1];
|
|
234
|
+
if (lastChild.typeID === TokenID.ERROR) return true;
|
|
235
|
+
if (isSemicolonToken(lastChild, expression)) return true;
|
|
236
|
+
if (lastChild.typeID === 38 && isErrorPlaceholder(lastChild)) return true;
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
function isErrorInBodySlot(errorNode, slot, generatorNode) {
|
|
240
|
+
if (slot.nodes.length === 0) {
|
|
241
|
+
const bodyStart = generatorNode.children[slot.headerEndIndex]?.from ?? generatorNode.from;
|
|
242
|
+
return errorNode.from >= bodyStart;
|
|
243
|
+
}
|
|
244
|
+
for (const bodyNode of slot.nodes) if (errorNode === bodyNode || isDescendantOf(bodyNode, errorNode)) {
|
|
245
|
+
if (isErrorPlaceholder(bodyNode)) return true;
|
|
246
|
+
if (bodyNode.typeID === 65 && isImpBlocksTailError(bodyNode, errorNode)) return true;
|
|
247
|
+
}
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
function isImpBlocksTailError(blocksNode, errorNode) {
|
|
251
|
+
const lastChild = blocksNode.children[blocksNode.children.length - 1];
|
|
252
|
+
return lastChild.typeID === TokenID.ERROR && (errorNode === lastChild || isDescendantOf(lastChild, errorNode));
|
|
253
|
+
}
|
|
254
|
+
function isErrorPlaceholder(node) {
|
|
255
|
+
if (node.typeID === TokenID.ERROR) return true;
|
|
256
|
+
if (node.children.length === 0) return false;
|
|
257
|
+
return node.children.every((child) => isErrorPlaceholder(child));
|
|
258
|
+
}
|
|
259
|
+
function isDescendantOf(ancestor, node) {
|
|
260
|
+
let current = node.parent;
|
|
261
|
+
while (current !== null) {
|
|
262
|
+
if (current === ancestor) return true;
|
|
263
|
+
current = current.parent;
|
|
264
|
+
}
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
function findRecursionInit(recursionNode, expression) {
|
|
268
|
+
const assignIndex = recursionNode.children.findIndex((child) => expression.slice(child.from, child.to) === ":=");
|
|
269
|
+
if (assignIndex < 0) return null;
|
|
270
|
+
for (let index = assignIndex + 1; index < recursionNode.children.length; index++) {
|
|
271
|
+
const child = recursionNode.children[index];
|
|
272
|
+
if (child.typeID === TokenID.ERROR) break;
|
|
273
|
+
if (isPipeToken(child, expression) || isClosingBrace(child, expression)) continue;
|
|
274
|
+
return child;
|
|
275
|
+
}
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
function incompleteGeneratorError(code, errorNode) {
|
|
279
|
+
return {
|
|
280
|
+
code,
|
|
281
|
+
from: errorNode.from,
|
|
282
|
+
to: errorNode.to
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
function isIncompleteGeneratorBodyCode(code) {
|
|
286
|
+
return code === RSErrorCode.expectedDeclarativeBody || code === RSErrorCode.expectedImperativeBody || code === RSErrorCode.expectedRecursiveBody;
|
|
287
|
+
}
|
|
288
|
+
function isPipeToken(node, expression) {
|
|
289
|
+
return expression.slice(node.from, node.to) === "|";
|
|
290
|
+
}
|
|
291
|
+
function isSemicolonToken(node, expression) {
|
|
292
|
+
return expression.slice(node.from, node.to) === ";";
|
|
293
|
+
}
|
|
294
|
+
function isClosingBrace(node, expression) {
|
|
295
|
+
return node.typeID !== TokenID.ERROR && expression.slice(node.from, node.to) === "}";
|
|
296
|
+
}
|
|
297
|
+
function isStructuralGeneratorToken(node, expression) {
|
|
298
|
+
const text = expression.slice(node.from, node.to);
|
|
299
|
+
return text === "{" || text === "}" || text === "|" || text === "∈" || text === ":=" || text === ";";
|
|
300
|
+
}
|
|
92
301
|
function subtreeHasError(node) {
|
|
93
302
|
if (node.typeID === TokenID.ERROR) return true;
|
|
94
303
|
return node.children.some(subtreeHasError);
|
|
@@ -145,6 +354,9 @@ function findAncestor(node, predicate) {
|
|
|
145
354
|
function isFunctionDeclNode(node) {
|
|
146
355
|
return node.typeID === 76 || node.typeID === TokenID.NT_FUNC_DEFINITION;
|
|
147
356
|
}
|
|
357
|
+
function isQuantifierNode(node) {
|
|
358
|
+
return node.typeID === 29;
|
|
359
|
+
}
|
|
148
360
|
function isFunctionNode(node) {
|
|
149
361
|
return node.typeID === 69 || node.typeID === TokenID.ID_FUNCTION;
|
|
150
362
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"syntax-errors.js","names":["TypeClassEnum"],"sources":["../../../src/rslang/parser/syntax-errors.ts"],"sourcesContent":["/**\n * Module: Syntactic errors reporting.\n */\n\nimport { type AstNode, visitAstDFS } from '../../parsing';\nimport { annotateError } from '../ast-annotations';\nimport { type ErrorReporter, RSErrorCode, type RSErrorDescription } from '../error';\nimport { type TypeClass, TypeClass as TypeClassEnum } from '../semantic/typification';\n\nimport { Arguments, Filter, Function, Function_decl, Predicate, Variable } from './parser.terms';\nimport { TokenID } from './token';\n\n/** Options for syntax error extraction. */\nexport interface SyntaxErrorOptions {\n expected?: TypeClass;\n}\n\n/** Extracts syntax errors from an AST. */\nexport function extractSyntaxErrors(\n ast: AstNode,\n expression: string,\n reporter: ErrorReporter,\n annotateErrors: boolean = false,\n options?: SyntaxErrorOptions\n) {\n const forbiddenErrors = extractForbiddenCharacterErrors(expression);\n if (forbiddenErrors.length > 0) {\n for (const error of forbiddenErrors) {\n reporter(error);\n if (annotateErrors) {\n annotateError(ast, error.code, error.params);\n }\n }\n return;\n }\n\n const collected: RSErrorDescription[] = [];\n const annotationTargets = new Map<RSErrorDescription, AstNode>();\n const collect = (error: RSErrorDescription, target?: AstNode) => {\n collected.push(error);\n if (target !== undefined) {\n annotationTargets.set(error, target);\n }\n };\n\n const bracketError = extractBracketErrors(expression);\n if (bracketError !== null) {\n collect(bracketError, ast);\n }\n const hasBracketErrors = bracketError !== null;\n visitAstDFS(ast, node => extractInternal(node, expression, collect, hasBracketErrors, options));\n\n for (const error of deduplicateErrors(collected)) {\n reporter(error);\n if (annotateErrors) {\n const target = annotationTargets.get(error);\n if (target !== undefined) {\n annotateError(target, error.code, error.params);\n }\n }\n }\n}\n\n// ====== Internals =========\nfunction extractInternal(\n node: AstNode,\n expression: string,\n collect: (error: RSErrorDescription, target: AstNode) => void,\n ignoreUnknownErrors: boolean,\n options?: SyntaxErrorOptions\n) {\n if (node.typeID !== TokenID.ERROR) {\n return;\n }\n\n function emit(target: AstNode, code: RSErrorCode, params?: readonly string[]) {\n collect({ code: code, from: target.from, to: target.to, params }, target);\n }\n\n const classified = classifyParseError(node, expression, options);\n if (classified !== null) {\n collect(classified, node);\n return;\n }\n\n const parent = node.parent;\n if (parent === null) {\n if (!ignoreUnknownErrors) {\n return emit(node, RSErrorCode.unknownSyntax);\n }\n return;\n }\n\n if (parent.typeID === Variable) {\n return emit(parent, RSErrorCode.expectedLocal);\n }\n\n if (!ignoreUnknownErrors) {\n emit(node.from === node.to ? parent : node, RSErrorCode.unknownSyntax);\n }\n}\n\nfunction classifyParseError(\n node: AstNode,\n expression: string,\n options?: SyntaxErrorOptions\n): RSErrorDescription | null {\n const incompleteFunctionDecl = detectIncompleteFunctionDecl(node, expression, options?.expected);\n if (incompleteFunctionDecl !== null) {\n return incompleteFunctionDecl;\n }\n\n const filterParen = detectFilterParenMismatch(node, expression);\n if (filterParen !== null) {\n return filterParen;\n }\n\n return detectGlobalFuncWithoutArgs(node, expression);\n}\n\nfunction detectIncompleteFunctionDecl(\n node: AstNode,\n expression: string,\n expected?: TypeClass\n): RSErrorDescription | null {\n const funcDecl = findAncestor(node, isFunctionDeclNode);\n if (funcDecl === null) {\n return null;\n }\n\n const bodyChild = funcDecl.children[funcDecl.children.length - 1];\n if (bodyChild?.typeID !== TokenID.ERROR || node !== bodyChild) {\n return null;\n }\n\n const argsNode = funcDecl.children.find(child => child.typeID === Arguments || child.typeID === TokenID.NT_ARGUMENTS);\n if (argsNode === undefined || subtreeHasError(argsNode)) {\n return null;\n }\n\n if (expression.slice(funcDecl.to).trim().length > 0) {\n return null;\n }\n\n return {\n code: incompleteFormalExpressionCode(expected),\n from: bodyChild.from,\n to: bodyChild.to\n };\n}\n\nfunction incompleteFormalExpressionCode(expected?: TypeClass): RSErrorCode {\n switch (expected) {\n case TypeClassEnum.function:\n return RSErrorCode.expectedExpressionBody;\n case TypeClassEnum.predicate:\n case TypeClassEnum.logic:\n return RSErrorCode.expectedLogicBody;\n default:\n return RSErrorCode.expectedFunctionBody;\n }\n}\n\nfunction subtreeHasError(node: AstNode): boolean {\n if (node.typeID === TokenID.ERROR) {\n return true;\n }\n return node.children.some(subtreeHasError);\n}\n\nfunction detectFilterParenMismatch(node: AstNode, expression: string): RSErrorDescription | null {\n const filterNode = findAncestor(node, isFilterNode) ?? findRelatedNode(node, isFilterNode);\n if (filterNode === null) {\n return null;\n }\n\n const nextChar = expression[filterNode.to];\n if (nextChar === '(') {\n return {\n code: RSErrorCode.invalidFilterSyntax,\n from: filterNode.from,\n to: filterNode.to + 1\n };\n }\n return null;\n}\n\nfunction detectGlobalFuncWithoutArgs(node: AstNode, expression: string): RSErrorDescription | null {\n const funcNode =\n findAncestor(node, n => isFunctionNode(n) || isPredicateNode(n)) ??\n findRelatedNode(node, n => isFunctionNode(n) || isPredicateNode(n));\n if (funcNode === null) {\n return null;\n }\n return classifyFuncWithoutArgs(funcNode, expression);\n}\n\nfunction findRelatedNode(node: AstNode, predicate: (target: AstNode) => boolean): AstNode | null {\n let current: AstNode | null = node.parent;\n while (current !== null) {\n for (const child of current.children) {\n if (predicate(child)) {\n return child;\n }\n }\n current = current.parent;\n }\n return null;\n}\n\nfunction classifyFuncWithoutArgs(funcNode: AstNode, expression: string): RSErrorDescription | null {\n const name = expression.slice(funcNode.from, funcNode.to);\n const rest = expression.slice(funcNode.to);\n\n const withoutArgs: RSErrorDescription = {\n code: RSErrorCode.globalFuncWithoutArgs,\n from: funcNode.from,\n to: funcNode.to,\n params: [name]\n };\n\n // Function with nothing (or only whitespace) after it is genuinely called without arguments.\n if (/^\\s*$/.test(rest)) {\n return withoutArgs;\n }\n\n // Anything other than a bracketed argument form (e.g. parentheses or braces) is malformed call\n // syntax: defer to the bracket/syntax error handling instead of reporting a missing-arguments error.\n const openBracket = /^\\s*\\[/.exec(rest);\n if (openBracket === null) {\n return null;\n }\n\n const closeIdx = findMatchingCloseBracket(rest, openBracket[0].length - 1);\n if (closeIdx >= 0) {\n const inner = rest.slice(openBracket[0].length, closeIdx).trim();\n if (inner.length === 0) {\n return withoutArgs;\n }\n }\n\n return null;\n}\n\nfunction findAncestor(node: AstNode, predicate: (node: AstNode) => boolean): AstNode | null {\n let current: AstNode | null = node;\n while (current !== null) {\n if (predicate(current)) {\n return current;\n }\n current = current.parent;\n }\n return null;\n}\n\nfunction isFunctionDeclNode(node: AstNode): boolean {\n return node.typeID === Function_decl || node.typeID === TokenID.NT_FUNC_DEFINITION;\n}\n\nfunction isFunctionNode(node: AstNode): boolean {\n return node.typeID === Function || node.typeID === TokenID.ID_FUNCTION;\n}\n\nfunction isPredicateNode(node: AstNode): boolean {\n return node.typeID === Predicate || node.typeID === TokenID.ID_PREDICATE;\n}\n\nfunction isFilterNode(node: AstNode): boolean {\n return node.typeID === Filter || node.typeID === TokenID.FILTER;\n}\n\nfunction findMatchingCloseBracket(expression: string, openPos: number): number {\n const open = expression[openPos];\n if (open !== '[') {\n return -1;\n }\n\n let depth = 0;\n for (let index = openPos; index < expression.length; index++) {\n const symbol = expression[index];\n if (symbol === '[') {\n depth++;\n } else if (symbol === ']') {\n depth--;\n if (depth === 0) {\n return index;\n }\n }\n }\n return -1;\n}\n\nfunction deduplicateErrors(errors: RSErrorDescription[]): RSErrorDescription[] {\n const result: RSErrorDescription[] = [];\n\n for (const error of errors) {\n const duplicate = result.some(\n existing => existing.code === error.code && existing.from === error.from && existing.to === error.to\n );\n if (duplicate) {\n continue;\n }\n\n if (error.code !== RSErrorCode.unknownSyntax) {\n for (let index = result.length - 1; index >= 0; index--) {\n if (result[index].code === RSErrorCode.unknownSyntax && rangesOverlap(error, result[index])) {\n result.splice(index, 1);\n }\n }\n }\n\n result.push(error);\n }\n\n const specific = result.filter(error => error.code !== RSErrorCode.unknownSyntax);\n return result.filter(\n error => error.code !== RSErrorCode.unknownSyntax || !specific.some(item => rangesOverlap(error, item))\n );\n}\n\nfunction rangesOverlap(a: RSErrorDescription, b: RSErrorDescription): boolean {\n return a.from < b.to && b.from < a.to;\n}\n\ntype OpenBracket = '(' | '[' | '{';\ntype CloseBracket = ')' | ']' | '}';\n\ninterface BracketFrame {\n bracket: OpenBracket;\n index: number;\n}\n\nconst ALLOWED_EXPRESSION_CHARS = buildAllowedExpressionChars();\n\nfunction buildAllowedExpressionChars(): Set<string> {\n const chars = new Set<string>();\n for (const chunk of [\n '0123456789',\n 'abcdefghijklmnopqrstuvwxyz',\n 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',\n '_',\n '∅¬∀∃⇔⇒∨&ℬ+-*∪\\\\∆∩×∈∉⊆⊄⊂<>≥≤≠=,:;|[]{}()'\n ]) {\n for (const symbol of chunk) {\n chars.add(symbol);\n }\n }\n for (let codePoint = 0x03b1; codePoint <= 0x03c9; codePoint++) {\n chars.add(String.fromCodePoint(codePoint));\n }\n return chars;\n}\n\nfunction isAllowedExpressionChar(symbol: string): boolean {\n return /\\s/u.test(symbol) || ALLOWED_EXPRESSION_CHARS.has(symbol);\n}\n\nfunction extractForbiddenCharacterErrors(expression: string): RSErrorDescription[] {\n const errors: RSErrorDescription[] = [];\n let pos = 0;\n\n while (pos < expression.length) {\n const symbol = expression[pos];\n if (isAllowedExpressionChar(symbol)) {\n pos++;\n continue;\n }\n\n const start = pos;\n while (pos < expression.length && !isAllowedExpressionChar(expression[pos])) {\n pos++;\n }\n\n errors.push({\n code: RSErrorCode.forbiddenCharacter,\n from: start,\n to: pos,\n params: [expression.slice(start, pos)]\n });\n }\n\n return errors;\n}\n\nfunction extractBracketErrors(expression: string): RSErrorDescription | null {\n const stack: BracketFrame[] = [];\n\n for (let pos = 0; pos < expression.length; pos++) {\n const symbol = expression[pos];\n if (isOpenBracket(symbol)) {\n if (isDoubleParenthesis(expression, pos)) {\n return {\n code: RSErrorCode.doubleParenthesis,\n from: pos,\n to: pos + 2\n };\n }\n stack.push({ bracket: symbol, index: pos });\n continue;\n }\n if (!isCloseBracket(symbol)) {\n continue;\n }\n\n const expectedOpen = closeToOpen(symbol);\n const top = stack[stack.length - 1];\n if (top === undefined) {\n return {\n code: RSErrorCode.missingOpenBracket,\n from: pos,\n to: pos + 1,\n params: [symbol]\n };\n }\n\n if (top.bracket !== expectedOpen) {\n return {\n code: RSErrorCode.bracketMismatch,\n from: pos,\n to: pos + 1,\n params: [openToClose(top.bracket), symbol]\n };\n }\n\n stack.pop();\n }\n\n if (stack.length > 0) {\n const unclosed = stack[0];\n return {\n code: RSErrorCode.missingCloseBracket,\n from: unclosed.index,\n to: unclosed.index + 1,\n params: [unclosed.bracket]\n };\n }\n\n return null;\n}\n\nfunction isOpenBracket(symbol: string): symbol is OpenBracket {\n return symbol === '(' || symbol === '[' || symbol === '{';\n}\n\nfunction isCloseBracket(symbol: string): symbol is CloseBracket {\n return symbol === ')' || symbol === ']' || symbol === '}';\n}\n\nfunction openToClose(symbol: OpenBracket): CloseBracket {\n switch (symbol) {\n case '(':\n return ')';\n case '[':\n return ']';\n case '{':\n return '}';\n }\n}\n\nfunction closeToOpen(symbol: CloseBracket): OpenBracket {\n switch (symbol) {\n case ')':\n return '(';\n case ']':\n return '[';\n case '}':\n return '{';\n }\n}\n\nfunction isDoubleParenthesis(expression: string, pos: number): boolean {\n const isOpenDoubleParenthesis = expression[pos] === '(' && expression[pos + 1] === '(';\n if (!isOpenDoubleParenthesis) {\n return false;\n }\n\n const outerClose = findMatchingCloseParen(expression, pos);\n const innerClose = findMatchingCloseParen(expression, pos + 1);\n if (outerClose < 0 || innerClose < 0) {\n return false;\n }\n\n return outerClose === innerClose + 1;\n}\n\nfunction findMatchingCloseParen(expression: string, openPos: number): number {\n if (expression[openPos] !== '(') {\n return -1;\n }\n\n const stack: OpenBracket[] = [];\n for (let index = openPos; index < expression.length; index++) {\n const symbol = expression[index];\n if (isOpenBracket(symbol)) {\n stack.push(symbol);\n continue;\n }\n if (!isCloseBracket(symbol)) {\n continue;\n }\n const top = stack.pop();\n if (top === undefined || top !== closeToOpen(symbol)) {\n return -1;\n }\n if (stack.length === 0) {\n return index;\n }\n }\n\n return -1;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"syntax-errors.js","names":["TypeClassEnum"],"sources":["../../../src/rslang/parser/syntax-errors.ts"],"sourcesContent":["/**\n * Module: Syntactic errors reporting.\n */\n\nimport { type AstNode, visitAstDFS } from '../../parsing';\nimport { annotateError } from '../ast-annotations';\nimport { type ErrorReporter, RSErrorCode, type RSErrorDescription } from '../error';\nimport { type TypeClass, TypeClass as TypeClassEnum } from '../semantic/typification';\n\nimport {\n Arguments,\n Declarative,\n Filter,\n Function,\n Function_decl,\n Imp_blocks,\n Imperative,\n Logic_quantor,\n Predicate,\n Recursion,\n Setexpr,\n Variable,\n Variable_pack\n} from './parser.terms';\nimport { TokenID } from './token';\n\n/** Options for syntax error extraction. */\nexport interface SyntaxErrorOptions {\n expected?: TypeClass;\n}\n\n/** Extracts syntax errors from an AST. */\nexport function extractSyntaxErrors(\n ast: AstNode,\n expression: string,\n reporter: ErrorReporter,\n annotateErrors: boolean = false,\n options?: SyntaxErrorOptions\n) {\n const forbiddenErrors = extractForbiddenCharacterErrors(expression);\n if (forbiddenErrors.length > 0) {\n for (const error of forbiddenErrors) {\n reporter(error);\n if (annotateErrors) {\n annotateError(ast, error.code, error.params);\n }\n }\n return;\n }\n\n const collected: RSErrorDescription[] = [];\n const annotationTargets = new Map<RSErrorDescription, AstNode>();\n const collect = (error: RSErrorDescription, target?: AstNode) => {\n collected.push(error);\n if (target !== undefined) {\n annotationTargets.set(error, target);\n }\n };\n\n const bracketError = extractBracketErrors(expression);\n const hasBracketErrors = bracketError !== null;\n visitAstDFS(ast, node => extractInternal(node, expression, collect, hasBracketErrors, options));\n\n const hasIncompleteGenerator = collected.some(error => isIncompleteGeneratorBodyCode(error.code));\n if (bracketError !== null && !hasIncompleteGenerator) {\n collect(bracketError, ast);\n }\n\n for (const error of deduplicateErrors(collected)) {\n reporter(error);\n if (annotateErrors) {\n const target = annotationTargets.get(error);\n if (target !== undefined) {\n annotateError(target, error.code, error.params);\n }\n }\n }\n}\n\n// ====== Internals =========\nfunction extractInternal(\n node: AstNode,\n expression: string,\n collect: (error: RSErrorDescription, target: AstNode) => void,\n ignoreUnknownErrors: boolean,\n options?: SyntaxErrorOptions\n) {\n if (node.typeID !== TokenID.ERROR) {\n return;\n }\n\n function emit(target: AstNode, code: RSErrorCode, params?: readonly string[]) {\n collect({ code: code, from: target.from, to: target.to, params }, target);\n }\n\n const classified = classifyParseError(node, expression, options);\n if (classified !== null) {\n collect(classified, node);\n return;\n }\n\n const parent = node.parent;\n if (parent === null) {\n if (!ignoreUnknownErrors) {\n return emit(node, RSErrorCode.unknownSyntax);\n }\n return;\n }\n\n if (parent.typeID === Variable) {\n return emit(parent, RSErrorCode.expectedLocal);\n }\n\n if (!ignoreUnknownErrors) {\n emit(node.from === node.to ? parent : node, RSErrorCode.unknownSyntax);\n }\n}\n\nfunction classifyParseError(\n node: AstNode,\n expression: string,\n options?: SyntaxErrorOptions\n): RSErrorDescription | null {\n const incompleteFunctionDecl = detectIncompleteFunctionDecl(node, expression, options?.expected);\n if (incompleteFunctionDecl !== null) {\n return incompleteFunctionDecl;\n }\n\n const incompleteQuantifier = detectIncompleteQuantifier(node, expression);\n if (incompleteQuantifier !== null) {\n return incompleteQuantifier;\n }\n\n const incompleteGenerator = detectIncompleteGenerator(node, expression);\n if (incompleteGenerator !== null) {\n return incompleteGenerator;\n }\n\n const filterParen = detectFilterParenMismatch(node, expression);\n if (filterParen !== null) {\n return filterParen;\n }\n\n return detectGlobalFuncWithoutArgs(node, expression);\n}\n\nfunction detectIncompleteFunctionDecl(\n node: AstNode,\n expression: string,\n expected?: TypeClass\n): RSErrorDescription | null {\n const funcDecl = findAncestor(node, isFunctionDeclNode);\n if (funcDecl === null) {\n return null;\n }\n\n const bodyChild = funcDecl.children[funcDecl.children.length - 1];\n if (bodyChild?.typeID !== TokenID.ERROR || node !== bodyChild) {\n return null;\n }\n\n const argsNode = funcDecl.children.find(child => child.typeID === Arguments || child.typeID === TokenID.NT_ARGUMENTS);\n if (argsNode === undefined || subtreeHasError(argsNode)) {\n return null;\n }\n\n if (expression.slice(funcDecl.to).trim().length > 0) {\n return null;\n }\n\n return {\n code: incompleteFormalExpressionCode(expected),\n from: bodyChild.from,\n to: bodyChild.to\n };\n}\n\nfunction incompleteFormalExpressionCode(expected?: TypeClass): RSErrorCode {\n switch (expected) {\n case TypeClassEnum.function:\n return RSErrorCode.expectedExpressionBody;\n case TypeClassEnum.predicate:\n case TypeClassEnum.logic:\n return RSErrorCode.expectedLogicBody;\n default:\n return RSErrorCode.expectedFunctionBody;\n }\n}\n\nfunction detectIncompleteQuantifier(node: AstNode, expression: string): RSErrorDescription | null {\n const quantNode = findAncestor(node, isQuantifierNode);\n if (quantNode === null) {\n return null;\n }\n\n const bodyChild = quantNode.children[quantNode.children.length - 1];\n if (bodyChild?.typeID !== TokenID.ERROR || node !== bodyChild) {\n return null;\n }\n\n const headerChildren = quantNode.children.slice(0, -1);\n if (headerChildren.length < 3) {\n return null;\n }\n\n const varPack = headerChildren.find(child => child.typeID === Variable_pack || child.typeID === TokenID.NT_ENUM_DECL);\n if (varPack === undefined || subtreeHasError(varPack)) {\n return null;\n }\n\n const domainChild = headerChildren[headerChildren.length - 1];\n if (domainChild === varPack || subtreeHasError(domainChild)) {\n return null;\n }\n\n if (expression.slice(quantNode.to).trim().length > 0) {\n return null;\n }\n\n return {\n code: RSErrorCode.expectedQuantifierBody,\n from: bodyChild.from,\n to: bodyChild.to\n };\n}\n\nfunction detectIncompleteGenerator(node: AstNode, expression: string): RSErrorDescription | null {\n return (\n detectIncompleteDeclarative(node, expression) ??\n detectIncompleteImperative(node, expression) ??\n detectIncompleteRecursion(node, expression)\n );\n}\n\nfunction detectIncompleteDeclarative(node: AstNode, expression: string): RSErrorDescription | null {\n const generatorNode = findAncestor(\n node,\n target => target.typeID === Declarative || target.typeID === TokenID.NT_DECLARATIVE_EXPR\n );\n return detectIncompleteGeneratorBody(node, expression, generatorNode, RSErrorCode.expectedDeclarativeBody, slot =>\n isIncompleteDeclarativeBody(slot)\n );\n}\n\nfunction detectIncompleteImperative(node: AstNode, expression: string): RSErrorDescription | null {\n const generatorNode = findAncestor(\n node,\n target => target.typeID === Imperative || target.typeID === TokenID.NT_IMPERATIVE_EXPR\n );\n return detectIncompleteGeneratorBody(node, expression, generatorNode, RSErrorCode.expectedImperativeBody, slot =>\n isIncompleteImperativeBody(slot, expression)\n );\n}\n\nfunction detectIncompleteRecursion(node: AstNode, expression: string): RSErrorDescription | null {\n const generatorNode = findAncestor(node, target => target.typeID === Recursion);\n return detectIncompleteGeneratorBody(node, expression, generatorNode, RSErrorCode.expectedRecursiveBody, slot =>\n isIncompleteRecursionBody(slot)\n );\n}\n\ninterface GeneratorBodySlot {\n nodes: AstNode[];\n headerEndIndex: number;\n}\n\nfunction detectIncompleteGeneratorBody(\n node: AstNode,\n expression: string,\n generatorNode: AstNode | null,\n code: RSErrorCode,\n isIncomplete: (slot: GeneratorBodySlot) => boolean\n): RSErrorDescription | null {\n if (generatorNode === null) {\n return null;\n }\n\n if (expression.slice(generatorNode.to).trim().length > 0) {\n return null;\n }\n\n const slot = getGeneratorBodySlot(generatorNode, expression);\n if (slot === null || !isIncomplete(slot)) {\n return null;\n }\n\n if (!generatorHeaderIsValid(generatorNode, expression, slot.headerEndIndex)) {\n return null;\n }\n\n if (!isErrorInBodySlot(node, slot, generatorNode)) {\n return null;\n }\n\n return incompleteGeneratorError(code, node);\n}\n\nfunction getGeneratorBodySlot(generatorNode: AstNode, expression: string): GeneratorBodySlot | null {\n if (generatorNode.typeID === Declarative || generatorNode.typeID === TokenID.NT_DECLARATIVE_EXPR) {\n return getDeclarativeBodySlot(generatorNode, expression);\n }\n if (generatorNode.typeID === Imperative || generatorNode.typeID === TokenID.NT_IMPERATIVE_EXPR) {\n return getImperativeBodySlot(generatorNode, expression);\n }\n if (generatorNode.typeID === Recursion) {\n return getRecursionBodySlot(generatorNode, expression);\n }\n return null;\n}\n\nfunction getDeclarativeBodySlot(declNode: AstNode, expression: string): GeneratorBodySlot | null {\n const pipeIndex = declNode.children.findIndex(child => isPipeToken(child, expression));\n if (pipeIndex >= 0) {\n return {\n nodes: contentChildren(declNode, expression, pipeIndex + 1),\n headerEndIndex: pipeIndex + 1\n };\n }\n\n const domainNode = findDeclarativeDomain(declNode, expression);\n if (domainNode === null) {\n return null;\n }\n\n const domainIndex = declNode.children.indexOf(domainNode);\n return {\n nodes: contentChildren(declNode, expression, domainIndex + 1),\n headerEndIndex: domainIndex + 1\n };\n}\n\nfunction getImperativeBodySlot(impNode: AstNode, expression: string): GeneratorBodySlot | null {\n const pipeIndex = impNode.children.findIndex(child => isPipeToken(child, expression));\n if (pipeIndex >= 0) {\n return {\n nodes: contentChildren(impNode, expression, pipeIndex + 1),\n headerEndIndex: pipeIndex + 1\n };\n }\n\n const tupleNode = findImperativeTuple(impNode);\n if (tupleNode === null) {\n return null;\n }\n\n const tupleIndex = impNode.children.indexOf(tupleNode);\n return {\n nodes: contentChildren(impNode, expression, tupleIndex + 1),\n headerEndIndex: tupleIndex + 1\n };\n}\n\nfunction getRecursionBodySlot(recNode: AstNode, expression: string): GeneratorBodySlot | null {\n const initNode = findRecursionInit(recNode, expression);\n if (initNode === null) {\n return null;\n }\n\n const initIndex = recNode.children.indexOf(initNode);\n const afterInit = contentChildren(recNode, expression, initIndex + 1);\n const lastPipeIndex = findLastPipeIndex(afterInit, expression);\n if (lastPipeIndex < 0) {\n return {\n nodes: afterInit,\n headerEndIndex: initIndex + 1\n };\n }\n\n return {\n nodes: afterInit.slice(lastPipeIndex + 1),\n headerEndIndex: recNode.children.indexOf(afterInit[lastPipeIndex]) + 1\n };\n}\n\nfunction contentChildren(generatorNode: AstNode, expression: string, fromIndex: number): AstNode[] {\n return generatorNode.children.slice(fromIndex).filter(child => !isClosingBrace(child, expression));\n}\n\nfunction findDeclarativeDomain(declNode: AstNode, expression: string): AstNode | null {\n const inIndex = declNode.children.findIndex(child => expression.slice(child.from, child.to) === '∈');\n if (inIndex < 0) {\n return null;\n }\n\n for (let index = inIndex + 1; index < declNode.children.length; index++) {\n const child = declNode.children[index];\n if (isPipeToken(child, expression) || isClosingBrace(child, expression)) {\n break;\n }\n if (child.typeID === Setexpr) {\n return child;\n }\n }\n\n return null;\n}\n\nfunction findImperativeTuple(impNode: AstNode): AstNode | null {\n for (const child of impNode.children) {\n if (child.typeID === Setexpr) {\n return child;\n }\n }\n return null;\n}\n\nfunction findLastPipeIndex(nodes: AstNode[], expression: string): number {\n for (let index = nodes.length - 1; index >= 0; index--) {\n if (isPipeToken(nodes[index], expression)) {\n return index;\n }\n }\n return -1;\n}\n\nfunction generatorHeaderIsValid(generatorNode: AstNode, expression: string, headerEndIndex: number): boolean {\n for (let index = 0; index < headerEndIndex; index++) {\n const child = generatorNode.children[index];\n if (child.typeID === TokenID.ERROR) {\n return false;\n }\n if (isStructuralGeneratorToken(child, expression)) {\n continue;\n }\n if (subtreeHasError(child)) {\n return false;\n }\n }\n return true;\n}\n\nfunction isIncompleteDeclarativeBody(slot: GeneratorBodySlot): boolean {\n return isEmptyOrErrorOnlyBody(slot.nodes);\n}\n\nfunction isIncompleteImperativeBody(slot: GeneratorBodySlot, expression: string): boolean {\n if (slot.nodes.length === 0) {\n return true;\n }\n if (slot.nodes.length === 1 && slot.nodes[0].typeID === Imp_blocks) {\n return isImpBlocksIncomplete(slot.nodes[0], expression);\n }\n return isEmptyOrErrorOnlyBody(slot.nodes);\n}\n\nfunction isIncompleteRecursionBody(slot: GeneratorBodySlot): boolean {\n return isEmptyOrErrorOnlyBody(slot.nodes);\n}\n\nfunction isEmptyOrErrorOnlyBody(nodes: AstNode[]): boolean {\n if (nodes.length === 0) {\n return true;\n }\n if (nodes.length === 1) {\n return isErrorPlaceholder(nodes[0]);\n }\n return false;\n}\n\nfunction isImpBlocksIncomplete(blocksNode: AstNode, expression: string): boolean {\n if (blocksNode.children.length === 0) {\n return true;\n }\n\n const lastChild = blocksNode.children[blocksNode.children.length - 1];\n if (lastChild.typeID === TokenID.ERROR) {\n return true;\n }\n if (isSemicolonToken(lastChild, expression)) {\n return true;\n }\n if (lastChild.typeID === Setexpr && isErrorPlaceholder(lastChild)) {\n return true;\n }\n\n return false;\n}\n\nfunction isErrorInBodySlot(errorNode: AstNode, slot: GeneratorBodySlot, generatorNode: AstNode): boolean {\n if (slot.nodes.length === 0) {\n const bodyStart = generatorNode.children[slot.headerEndIndex]?.from ?? generatorNode.from;\n return errorNode.from >= bodyStart;\n }\n\n for (const bodyNode of slot.nodes) {\n if (errorNode === bodyNode || isDescendantOf(bodyNode, errorNode)) {\n if (isErrorPlaceholder(bodyNode)) {\n return true;\n }\n if (bodyNode.typeID === Imp_blocks && isImpBlocksTailError(bodyNode, errorNode)) {\n return true;\n }\n }\n }\n\n return false;\n}\n\nfunction isImpBlocksTailError(blocksNode: AstNode, errorNode: AstNode): boolean {\n const lastChild = blocksNode.children[blocksNode.children.length - 1];\n return lastChild.typeID === TokenID.ERROR && (errorNode === lastChild || isDescendantOf(lastChild, errorNode));\n}\n\nfunction isErrorPlaceholder(node: AstNode): boolean {\n if (node.typeID === TokenID.ERROR) {\n return true;\n }\n if (node.children.length === 0) {\n return false;\n }\n return node.children.every(child => isErrorPlaceholder(child));\n}\n\nfunction isDescendantOf(ancestor: AstNode, node: AstNode): boolean {\n let current: AstNode | null = node.parent;\n while (current !== null) {\n if (current === ancestor) {\n return true;\n }\n current = current.parent;\n }\n return false;\n}\n\nfunction findRecursionInit(recursionNode: AstNode, expression: string): AstNode | null {\n const assignIndex = recursionNode.children.findIndex(child => expression.slice(child.from, child.to) === ':=');\n if (assignIndex < 0) {\n return null;\n }\n\n for (let index = assignIndex + 1; index < recursionNode.children.length; index++) {\n const child = recursionNode.children[index];\n if (child.typeID === TokenID.ERROR) {\n break;\n }\n if (isPipeToken(child, expression) || isClosingBrace(child, expression)) {\n continue;\n }\n return child;\n }\n\n return null;\n}\n\nfunction incompleteGeneratorError(code: RSErrorCode, errorNode: AstNode): RSErrorDescription {\n return {\n code,\n from: errorNode.from,\n to: errorNode.to\n };\n}\n\nfunction isIncompleteGeneratorBodyCode(code: RSErrorCode): boolean {\n return (\n code === RSErrorCode.expectedDeclarativeBody ||\n code === RSErrorCode.expectedImperativeBody ||\n code === RSErrorCode.expectedRecursiveBody\n );\n}\n\nfunction isPipeToken(node: AstNode, expression: string): boolean {\n return expression.slice(node.from, node.to) === '|';\n}\n\nfunction isSemicolonToken(node: AstNode, expression: string): boolean {\n return expression.slice(node.from, node.to) === ';';\n}\n\nfunction isClosingBrace(node: AstNode, expression: string): boolean {\n return node.typeID !== TokenID.ERROR && expression.slice(node.from, node.to) === '}';\n}\n\nfunction isStructuralGeneratorToken(node: AstNode, expression: string): boolean {\n const text = expression.slice(node.from, node.to);\n return text === '{' || text === '}' || text === '|' || text === '∈' || text === ':=' || text === ';';\n}\n\nfunction subtreeHasError(node: AstNode): boolean {\n if (node.typeID === TokenID.ERROR) {\n return true;\n }\n return node.children.some(subtreeHasError);\n}\n\nfunction detectFilterParenMismatch(node: AstNode, expression: string): RSErrorDescription | null {\n const filterNode = findAncestor(node, isFilterNode) ?? findRelatedNode(node, isFilterNode);\n if (filterNode === null) {\n return null;\n }\n\n const nextChar = expression[filterNode.to];\n if (nextChar === '(') {\n return {\n code: RSErrorCode.invalidFilterSyntax,\n from: filterNode.from,\n to: filterNode.to + 1\n };\n }\n return null;\n}\n\nfunction detectGlobalFuncWithoutArgs(node: AstNode, expression: string): RSErrorDescription | null {\n const funcNode =\n findAncestor(node, n => isFunctionNode(n) || isPredicateNode(n)) ??\n findRelatedNode(node, n => isFunctionNode(n) || isPredicateNode(n));\n if (funcNode === null) {\n return null;\n }\n return classifyFuncWithoutArgs(funcNode, expression);\n}\n\nfunction findRelatedNode(node: AstNode, predicate: (target: AstNode) => boolean): AstNode | null {\n let current: AstNode | null = node.parent;\n while (current !== null) {\n for (const child of current.children) {\n if (predicate(child)) {\n return child;\n }\n }\n current = current.parent;\n }\n return null;\n}\n\nfunction classifyFuncWithoutArgs(funcNode: AstNode, expression: string): RSErrorDescription | null {\n const name = expression.slice(funcNode.from, funcNode.to);\n const rest = expression.slice(funcNode.to);\n\n const withoutArgs: RSErrorDescription = {\n code: RSErrorCode.globalFuncWithoutArgs,\n from: funcNode.from,\n to: funcNode.to,\n params: [name]\n };\n\n // Function with nothing (or only whitespace) after it is genuinely called without arguments.\n if (/^\\s*$/.test(rest)) {\n return withoutArgs;\n }\n\n // Anything other than a bracketed argument form (e.g. parentheses or braces) is malformed call\n // syntax: defer to the bracket/syntax error handling instead of reporting a missing-arguments error.\n const openBracket = /^\\s*\\[/.exec(rest);\n if (openBracket === null) {\n return null;\n }\n\n const closeIdx = findMatchingCloseBracket(rest, openBracket[0].length - 1);\n if (closeIdx >= 0) {\n const inner = rest.slice(openBracket[0].length, closeIdx).trim();\n if (inner.length === 0) {\n return withoutArgs;\n }\n }\n\n return null;\n}\n\nfunction findAncestor(node: AstNode, predicate: (node: AstNode) => boolean): AstNode | null {\n let current: AstNode | null = node;\n while (current !== null) {\n if (predicate(current)) {\n return current;\n }\n current = current.parent;\n }\n return null;\n}\n\nfunction isFunctionDeclNode(node: AstNode): boolean {\n return node.typeID === Function_decl || node.typeID === TokenID.NT_FUNC_DEFINITION;\n}\n\nfunction isQuantifierNode(node: AstNode): boolean {\n return node.typeID === Logic_quantor;\n}\n\nfunction isFunctionNode(node: AstNode): boolean {\n return node.typeID === Function || node.typeID === TokenID.ID_FUNCTION;\n}\n\nfunction isPredicateNode(node: AstNode): boolean {\n return node.typeID === Predicate || node.typeID === TokenID.ID_PREDICATE;\n}\n\nfunction isFilterNode(node: AstNode): boolean {\n return node.typeID === Filter || node.typeID === TokenID.FILTER;\n}\n\nfunction findMatchingCloseBracket(expression: string, openPos: number): number {\n const open = expression[openPos];\n if (open !== '[') {\n return -1;\n }\n\n let depth = 0;\n for (let index = openPos; index < expression.length; index++) {\n const symbol = expression[index];\n if (symbol === '[') {\n depth++;\n } else if (symbol === ']') {\n depth--;\n if (depth === 0) {\n return index;\n }\n }\n }\n return -1;\n}\n\nfunction deduplicateErrors(errors: RSErrorDescription[]): RSErrorDescription[] {\n const result: RSErrorDescription[] = [];\n\n for (const error of errors) {\n const duplicate = result.some(\n existing => existing.code === error.code && existing.from === error.from && existing.to === error.to\n );\n if (duplicate) {\n continue;\n }\n\n if (error.code !== RSErrorCode.unknownSyntax) {\n for (let index = result.length - 1; index >= 0; index--) {\n if (result[index].code === RSErrorCode.unknownSyntax && rangesOverlap(error, result[index])) {\n result.splice(index, 1);\n }\n }\n }\n\n result.push(error);\n }\n\n const specific = result.filter(error => error.code !== RSErrorCode.unknownSyntax);\n return result.filter(\n error => error.code !== RSErrorCode.unknownSyntax || !specific.some(item => rangesOverlap(error, item))\n );\n}\n\nfunction rangesOverlap(a: RSErrorDescription, b: RSErrorDescription): boolean {\n return a.from < b.to && b.from < a.to;\n}\n\ntype OpenBracket = '(' | '[' | '{';\ntype CloseBracket = ')' | ']' | '}';\n\ninterface BracketFrame {\n bracket: OpenBracket;\n index: number;\n}\n\nconst ALLOWED_EXPRESSION_CHARS = buildAllowedExpressionChars();\n\nfunction buildAllowedExpressionChars(): Set<string> {\n const chars = new Set<string>();\n for (const chunk of [\n '0123456789',\n 'abcdefghijklmnopqrstuvwxyz',\n 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',\n '_',\n '∅¬∀∃⇔⇒∨&ℬ+-*∪\\\\∆∩×∈∉⊆⊄⊂<>≥≤≠=,:;|[]{}()'\n ]) {\n for (const symbol of chunk) {\n chars.add(symbol);\n }\n }\n for (let codePoint = 0x03b1; codePoint <= 0x03c9; codePoint++) {\n chars.add(String.fromCodePoint(codePoint));\n }\n return chars;\n}\n\nfunction isAllowedExpressionChar(symbol: string): boolean {\n return /\\s/u.test(symbol) || ALLOWED_EXPRESSION_CHARS.has(symbol);\n}\n\nfunction extractForbiddenCharacterErrors(expression: string): RSErrorDescription[] {\n const errors: RSErrorDescription[] = [];\n let pos = 0;\n\n while (pos < expression.length) {\n const symbol = expression[pos];\n if (isAllowedExpressionChar(symbol)) {\n pos++;\n continue;\n }\n\n const start = pos;\n while (pos < expression.length && !isAllowedExpressionChar(expression[pos])) {\n pos++;\n }\n\n errors.push({\n code: RSErrorCode.forbiddenCharacter,\n from: start,\n to: pos,\n params: [expression.slice(start, pos)]\n });\n }\n\n return errors;\n}\n\nfunction extractBracketErrors(expression: string): RSErrorDescription | null {\n const stack: BracketFrame[] = [];\n\n for (let pos = 0; pos < expression.length; pos++) {\n const symbol = expression[pos];\n if (isOpenBracket(symbol)) {\n if (isDoubleParenthesis(expression, pos)) {\n return {\n code: RSErrorCode.doubleParenthesis,\n from: pos,\n to: pos + 2\n };\n }\n stack.push({ bracket: symbol, index: pos });\n continue;\n }\n if (!isCloseBracket(symbol)) {\n continue;\n }\n\n const expectedOpen = closeToOpen(symbol);\n const top = stack[stack.length - 1];\n if (top === undefined) {\n return {\n code: RSErrorCode.missingOpenBracket,\n from: pos,\n to: pos + 1,\n params: [symbol]\n };\n }\n\n if (top.bracket !== expectedOpen) {\n return {\n code: RSErrorCode.bracketMismatch,\n from: pos,\n to: pos + 1,\n params: [openToClose(top.bracket), symbol]\n };\n }\n\n stack.pop();\n }\n\n if (stack.length > 0) {\n const unclosed = stack[0];\n return {\n code: RSErrorCode.missingCloseBracket,\n from: unclosed.index,\n to: unclosed.index + 1,\n params: [unclosed.bracket]\n };\n }\n\n return null;\n}\n\nfunction isOpenBracket(symbol: string): symbol is OpenBracket {\n return symbol === '(' || symbol === '[' || symbol === '{';\n}\n\nfunction isCloseBracket(symbol: string): symbol is CloseBracket {\n return symbol === ')' || symbol === ']' || symbol === '}';\n}\n\nfunction openToClose(symbol: OpenBracket): CloseBracket {\n switch (symbol) {\n case '(':\n return ')';\n case '[':\n return ']';\n case '{':\n return '}';\n }\n}\n\nfunction closeToOpen(symbol: CloseBracket): OpenBracket {\n switch (symbol) {\n case ')':\n return '(';\n case ']':\n return '[';\n case '}':\n return '{';\n }\n}\n\nfunction isDoubleParenthesis(expression: string, pos: number): boolean {\n const isOpenDoubleParenthesis = expression[pos] === '(' && expression[pos + 1] === '(';\n if (!isOpenDoubleParenthesis) {\n return false;\n }\n\n const outerClose = findMatchingCloseParen(expression, pos);\n const innerClose = findMatchingCloseParen(expression, pos + 1);\n if (outerClose < 0 || innerClose < 0) {\n return false;\n }\n\n return outerClose === innerClose + 1;\n}\n\nfunction findMatchingCloseParen(expression: string, openPos: number): number {\n if (expression[openPos] !== '(') {\n return -1;\n }\n\n const stack: OpenBracket[] = [];\n for (let index = openPos; index < expression.length; index++) {\n const symbol = expression[index];\n if (isOpenBracket(symbol)) {\n stack.push(symbol);\n continue;\n }\n if (!isCloseBracket(symbol)) {\n continue;\n }\n const top = stack.pop();\n if (top === undefined || top !== closeToOpen(symbol)) {\n return -1;\n }\n if (stack.length === 0) {\n return index;\n }\n }\n\n return -1;\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as RSLangAnalyzer, i as AnalysisOptions, n as AnalysisFast, r as AnalysisFull, t as AnalysisBase } from "../../analyzer-
|
|
1
|
+
import { a as RSLangAnalyzer, i as AnalysisOptions, n as AnalysisFast, r as AnalysisFull, t as AnalysisBase } from "../../analyzer-CqUJ3FO9.js";
|
|
2
2
|
export { AnalysisBase, AnalysisFast, AnalysisFull, AnalysisOptions, RSLangAnalyzer };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as AstNode } from "../../ast-C8sIpKdL.js";
|
|
2
2
|
import { _ as TypeContext, f as ExpressionType } from "../../typification-Dk-fisgO.js";
|
|
3
|
-
import { t as ErrorReporter } from "../../error-
|
|
3
|
+
import { t as ErrorReporter } from "../../error-CLnXbkly.js";
|
|
4
4
|
|
|
5
5
|
//#region src/rslang/semantic/type-auditor.d.ts
|
|
6
6
|
/** Type auditor for AST type checking. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as AstNode } from "../../ast-C8sIpKdL.js";
|
|
2
|
-
import { t as ErrorReporter } from "../../error-
|
|
2
|
+
import { t as ErrorReporter } from "../../error-CLnXbkly.js";
|
|
3
3
|
import { n as ValueClassContext, t as ValueClass } from "../../value-class-CNI-lqXJ.js";
|
|
4
4
|
|
|
5
5
|
//#region src/rslang/semantic/value-auditor.d.ts
|
package/package.json
CHANGED
package/src/rslang/error.ts
CHANGED
|
@@ -37,6 +37,10 @@ export const RSErrorCode = {
|
|
|
37
37
|
expectedFunctionBody: 0x8418, // 33816
|
|
38
38
|
expectedExpressionBody: 0x8419, // 33817
|
|
39
39
|
expectedLogicBody: 0x841a, // 33818
|
|
40
|
+
expectedQuantifierBody: 0x841b, // 33819
|
|
41
|
+
expectedDeclarativeBody: 0x841c, // 33820
|
|
42
|
+
expectedImperativeBody: 0x841d, // 33821
|
|
43
|
+
expectedRecursiveBody: 0x841e, // 33822
|
|
40
44
|
expectedLocal: 0x8415, // 33813
|
|
41
45
|
expectedType: 0x8416, // 33814
|
|
42
46
|
|
|
@@ -91,9 +91,20 @@ const testErrorData = [
|
|
|
91
91
|
];
|
|
92
92
|
|
|
93
93
|
const testIncompleteFormalData = [
|
|
94
|
-
['[α∈ℬ(X1×X1)]', TypeClass.function, RSErrorCode.expectedExpressionBody],
|
|
95
|
-
['[σ∈S1]', TypeClass.predicate, RSErrorCode.expectedLogicBody],
|
|
96
|
-
['[ξ∈X1]', TypeClass.logic, RSErrorCode.expectedLogicBody]
|
|
94
|
+
['[α∈ℬ(X1×X1)]', TypeClass.function, { code: RSErrorCode.expectedExpressionBody, from: 12, to: 12 }],
|
|
95
|
+
['[σ∈S1]', TypeClass.predicate, { code: RSErrorCode.expectedLogicBody, from: 6, to: 6 }],
|
|
96
|
+
['[ξ∈X1]', TypeClass.logic, { code: RSErrorCode.expectedLogicBody, from: 6, to: 6 }],
|
|
97
|
+
['∀α∈X1', TypeClass.logic, { code: RSErrorCode.expectedQuantifierBody, from: 5, to: 5 }],
|
|
98
|
+
['∃β∈S2', TypeClass.logic, { code: RSErrorCode.expectedQuantifierBody, from: 5, to: 5 }],
|
|
99
|
+
['D{ξ∈X1 |', TypeClass.function, { code: RSErrorCode.expectedDeclarativeBody, from: 8, to: 8 }],
|
|
100
|
+
['D{ξ∈X1 |}', TypeClass.function, { code: RSErrorCode.expectedDeclarativeBody, from: 8, to: 8 }],
|
|
101
|
+
['D{ξ∈X1}', TypeClass.function, { code: RSErrorCode.expectedDeclarativeBody, from: 6, to: 7 }],
|
|
102
|
+
['I{(σ, γ) |}', TypeClass.function, { code: RSErrorCode.expectedImperativeBody, from: 10, to: 10 }],
|
|
103
|
+
['I{(σ, γ)}', TypeClass.function, { code: RSErrorCode.expectedImperativeBody, from: 8, to: 9 }],
|
|
104
|
+
['I{(σ, γ) | σ:∈X1;}', TypeClass.function, { code: RSErrorCode.expectedImperativeBody, from: 17, to: 17 }],
|
|
105
|
+
['R{ξ:=D1 |}', TypeClass.function, { code: RSErrorCode.expectedRecursiveBody, from: 9, to: 9 }],
|
|
106
|
+
['R{ξ:=D1 | F1[ξ]≠∅ |}', TypeClass.function, { code: RSErrorCode.expectedRecursiveBody, from: 19, to: 19 }],
|
|
107
|
+
['R{ξ:=D1}', TypeClass.function, { code: RSErrorCode.expectedRecursiveBody, from: 7, to: 8 }]
|
|
97
108
|
] as const;
|
|
98
109
|
|
|
99
110
|
describe('Testing RSParser correct inputs', () => {
|
|
@@ -127,15 +138,14 @@ describe('Testing RSParser error data', () => {
|
|
|
127
138
|
});
|
|
128
139
|
});
|
|
129
140
|
|
|
130
|
-
testIncompleteFormalData.forEach(([input, expected,
|
|
141
|
+
testIncompleteFormalData.forEach(([input, expected, expectedError]) => {
|
|
131
142
|
it(`Parse incomplete formal "${input}" for ${expected}`, () => {
|
|
132
143
|
const tree = parser.parse(input);
|
|
133
144
|
const ast = buildTree(tree.cursor());
|
|
134
145
|
const errors: RSErrorDescription[] = [];
|
|
135
146
|
extractSyntaxErrors(ast, input, error => errors.push(error), false, { expected });
|
|
136
147
|
expect(errors.length).toBe(1);
|
|
137
|
-
expect(errors[0]
|
|
138
|
-
expect(errors[0].from).toBe(errors[0].to);
|
|
148
|
+
expect(errors[0]).toMatchObject(expectedError);
|
|
139
149
|
});
|
|
140
150
|
});
|
|
141
151
|
|
|
@@ -182,6 +192,29 @@ describe('Testing RSParser error data', () => {
|
|
|
182
192
|
expect(errorsTuple.some(error => error.code === RSErrorCode.doubleParenthesis)).toBe(false);
|
|
183
193
|
});
|
|
184
194
|
|
|
195
|
+
it('Does not treat malformed generator body as incomplete', () => {
|
|
196
|
+
const input = 'D{ξ∈X1 | P1[';
|
|
197
|
+
const tree = parser.parse(input);
|
|
198
|
+
const ast = buildTree(tree.cursor());
|
|
199
|
+
const errors: RSErrorDescription[] = [];
|
|
200
|
+
extractSyntaxErrors(ast, input, error => errors.push(error));
|
|
201
|
+
expect(errors.some(error => error.code === RSErrorCode.expectedDeclarativeBody)).toBe(false);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('Reports incomplete quantifier only for innermost missing body', () => {
|
|
205
|
+
const input = '∀α∈X1 ∀β∈X2';
|
|
206
|
+
const tree = parser.parse(input);
|
|
207
|
+
const ast = buildTree(tree.cursor());
|
|
208
|
+
const errors: RSErrorDescription[] = [];
|
|
209
|
+
extractSyntaxErrors(ast, input, error => errors.push(error), false, { expected: TypeClass.logic });
|
|
210
|
+
expect(errors.length).toBe(1);
|
|
211
|
+
expect(errors[0]).toMatchObject({
|
|
212
|
+
code: RSErrorCode.expectedQuantifierBody,
|
|
213
|
+
from: input.length,
|
|
214
|
+
to: input.length
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
|
|
185
218
|
it('Reports a single forbidden-character error for exponentiation', () => {
|
|
186
219
|
const input = '[σ∈S2]I{γ | ξ:∈ℬ(σ); γ:=(ξ×{1})∪((σ\\ξ)×{0}); 16=2^4}';
|
|
187
220
|
const tree = parser.parse(input);
|
|
@@ -7,7 +7,21 @@ import { annotateError } from '../ast-annotations';
|
|
|
7
7
|
import { type ErrorReporter, RSErrorCode, type RSErrorDescription } from '../error';
|
|
8
8
|
import { type TypeClass, TypeClass as TypeClassEnum } from '../semantic/typification';
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
Arguments,
|
|
12
|
+
Declarative,
|
|
13
|
+
Filter,
|
|
14
|
+
Function,
|
|
15
|
+
Function_decl,
|
|
16
|
+
Imp_blocks,
|
|
17
|
+
Imperative,
|
|
18
|
+
Logic_quantor,
|
|
19
|
+
Predicate,
|
|
20
|
+
Recursion,
|
|
21
|
+
Setexpr,
|
|
22
|
+
Variable,
|
|
23
|
+
Variable_pack
|
|
24
|
+
} from './parser.terms';
|
|
11
25
|
import { TokenID } from './token';
|
|
12
26
|
|
|
13
27
|
/** Options for syntax error extraction. */
|
|
@@ -44,12 +58,14 @@ export function extractSyntaxErrors(
|
|
|
44
58
|
};
|
|
45
59
|
|
|
46
60
|
const bracketError = extractBracketErrors(expression);
|
|
47
|
-
if (bracketError !== null) {
|
|
48
|
-
collect(bracketError, ast);
|
|
49
|
-
}
|
|
50
61
|
const hasBracketErrors = bracketError !== null;
|
|
51
62
|
visitAstDFS(ast, node => extractInternal(node, expression, collect, hasBracketErrors, options));
|
|
52
63
|
|
|
64
|
+
const hasIncompleteGenerator = collected.some(error => isIncompleteGeneratorBodyCode(error.code));
|
|
65
|
+
if (bracketError !== null && !hasIncompleteGenerator) {
|
|
66
|
+
collect(bracketError, ast);
|
|
67
|
+
}
|
|
68
|
+
|
|
53
69
|
for (const error of deduplicateErrors(collected)) {
|
|
54
70
|
reporter(error);
|
|
55
71
|
if (annotateErrors) {
|
|
@@ -110,6 +126,16 @@ function classifyParseError(
|
|
|
110
126
|
return incompleteFunctionDecl;
|
|
111
127
|
}
|
|
112
128
|
|
|
129
|
+
const incompleteQuantifier = detectIncompleteQuantifier(node, expression);
|
|
130
|
+
if (incompleteQuantifier !== null) {
|
|
131
|
+
return incompleteQuantifier;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const incompleteGenerator = detectIncompleteGenerator(node, expression);
|
|
135
|
+
if (incompleteGenerator !== null) {
|
|
136
|
+
return incompleteGenerator;
|
|
137
|
+
}
|
|
138
|
+
|
|
113
139
|
const filterParen = detectFilterParenMismatch(node, expression);
|
|
114
140
|
if (filterParen !== null) {
|
|
115
141
|
return filterParen;
|
|
@@ -161,6 +187,394 @@ function incompleteFormalExpressionCode(expected?: TypeClass): RSErrorCode {
|
|
|
161
187
|
}
|
|
162
188
|
}
|
|
163
189
|
|
|
190
|
+
function detectIncompleteQuantifier(node: AstNode, expression: string): RSErrorDescription | null {
|
|
191
|
+
const quantNode = findAncestor(node, isQuantifierNode);
|
|
192
|
+
if (quantNode === null) {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const bodyChild = quantNode.children[quantNode.children.length - 1];
|
|
197
|
+
if (bodyChild?.typeID !== TokenID.ERROR || node !== bodyChild) {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const headerChildren = quantNode.children.slice(0, -1);
|
|
202
|
+
if (headerChildren.length < 3) {
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const varPack = headerChildren.find(child => child.typeID === Variable_pack || child.typeID === TokenID.NT_ENUM_DECL);
|
|
207
|
+
if (varPack === undefined || subtreeHasError(varPack)) {
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const domainChild = headerChildren[headerChildren.length - 1];
|
|
212
|
+
if (domainChild === varPack || subtreeHasError(domainChild)) {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (expression.slice(quantNode.to).trim().length > 0) {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
code: RSErrorCode.expectedQuantifierBody,
|
|
222
|
+
from: bodyChild.from,
|
|
223
|
+
to: bodyChild.to
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function detectIncompleteGenerator(node: AstNode, expression: string): RSErrorDescription | null {
|
|
228
|
+
return (
|
|
229
|
+
detectIncompleteDeclarative(node, expression) ??
|
|
230
|
+
detectIncompleteImperative(node, expression) ??
|
|
231
|
+
detectIncompleteRecursion(node, expression)
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function detectIncompleteDeclarative(node: AstNode, expression: string): RSErrorDescription | null {
|
|
236
|
+
const generatorNode = findAncestor(
|
|
237
|
+
node,
|
|
238
|
+
target => target.typeID === Declarative || target.typeID === TokenID.NT_DECLARATIVE_EXPR
|
|
239
|
+
);
|
|
240
|
+
return detectIncompleteGeneratorBody(node, expression, generatorNode, RSErrorCode.expectedDeclarativeBody, slot =>
|
|
241
|
+
isIncompleteDeclarativeBody(slot)
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function detectIncompleteImperative(node: AstNode, expression: string): RSErrorDescription | null {
|
|
246
|
+
const generatorNode = findAncestor(
|
|
247
|
+
node,
|
|
248
|
+
target => target.typeID === Imperative || target.typeID === TokenID.NT_IMPERATIVE_EXPR
|
|
249
|
+
);
|
|
250
|
+
return detectIncompleteGeneratorBody(node, expression, generatorNode, RSErrorCode.expectedImperativeBody, slot =>
|
|
251
|
+
isIncompleteImperativeBody(slot, expression)
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function detectIncompleteRecursion(node: AstNode, expression: string): RSErrorDescription | null {
|
|
256
|
+
const generatorNode = findAncestor(node, target => target.typeID === Recursion);
|
|
257
|
+
return detectIncompleteGeneratorBody(node, expression, generatorNode, RSErrorCode.expectedRecursiveBody, slot =>
|
|
258
|
+
isIncompleteRecursionBody(slot)
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
interface GeneratorBodySlot {
|
|
263
|
+
nodes: AstNode[];
|
|
264
|
+
headerEndIndex: number;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function detectIncompleteGeneratorBody(
|
|
268
|
+
node: AstNode,
|
|
269
|
+
expression: string,
|
|
270
|
+
generatorNode: AstNode | null,
|
|
271
|
+
code: RSErrorCode,
|
|
272
|
+
isIncomplete: (slot: GeneratorBodySlot) => boolean
|
|
273
|
+
): RSErrorDescription | null {
|
|
274
|
+
if (generatorNode === null) {
|
|
275
|
+
return null;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (expression.slice(generatorNode.to).trim().length > 0) {
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const slot = getGeneratorBodySlot(generatorNode, expression);
|
|
283
|
+
if (slot === null || !isIncomplete(slot)) {
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (!generatorHeaderIsValid(generatorNode, expression, slot.headerEndIndex)) {
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (!isErrorInBodySlot(node, slot, generatorNode)) {
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return incompleteGeneratorError(code, node);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function getGeneratorBodySlot(generatorNode: AstNode, expression: string): GeneratorBodySlot | null {
|
|
299
|
+
if (generatorNode.typeID === Declarative || generatorNode.typeID === TokenID.NT_DECLARATIVE_EXPR) {
|
|
300
|
+
return getDeclarativeBodySlot(generatorNode, expression);
|
|
301
|
+
}
|
|
302
|
+
if (generatorNode.typeID === Imperative || generatorNode.typeID === TokenID.NT_IMPERATIVE_EXPR) {
|
|
303
|
+
return getImperativeBodySlot(generatorNode, expression);
|
|
304
|
+
}
|
|
305
|
+
if (generatorNode.typeID === Recursion) {
|
|
306
|
+
return getRecursionBodySlot(generatorNode, expression);
|
|
307
|
+
}
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function getDeclarativeBodySlot(declNode: AstNode, expression: string): GeneratorBodySlot | null {
|
|
312
|
+
const pipeIndex = declNode.children.findIndex(child => isPipeToken(child, expression));
|
|
313
|
+
if (pipeIndex >= 0) {
|
|
314
|
+
return {
|
|
315
|
+
nodes: contentChildren(declNode, expression, pipeIndex + 1),
|
|
316
|
+
headerEndIndex: pipeIndex + 1
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const domainNode = findDeclarativeDomain(declNode, expression);
|
|
321
|
+
if (domainNode === null) {
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const domainIndex = declNode.children.indexOf(domainNode);
|
|
326
|
+
return {
|
|
327
|
+
nodes: contentChildren(declNode, expression, domainIndex + 1),
|
|
328
|
+
headerEndIndex: domainIndex + 1
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function getImperativeBodySlot(impNode: AstNode, expression: string): GeneratorBodySlot | null {
|
|
333
|
+
const pipeIndex = impNode.children.findIndex(child => isPipeToken(child, expression));
|
|
334
|
+
if (pipeIndex >= 0) {
|
|
335
|
+
return {
|
|
336
|
+
nodes: contentChildren(impNode, expression, pipeIndex + 1),
|
|
337
|
+
headerEndIndex: pipeIndex + 1
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const tupleNode = findImperativeTuple(impNode);
|
|
342
|
+
if (tupleNode === null) {
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const tupleIndex = impNode.children.indexOf(tupleNode);
|
|
347
|
+
return {
|
|
348
|
+
nodes: contentChildren(impNode, expression, tupleIndex + 1),
|
|
349
|
+
headerEndIndex: tupleIndex + 1
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function getRecursionBodySlot(recNode: AstNode, expression: string): GeneratorBodySlot | null {
|
|
354
|
+
const initNode = findRecursionInit(recNode, expression);
|
|
355
|
+
if (initNode === null) {
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const initIndex = recNode.children.indexOf(initNode);
|
|
360
|
+
const afterInit = contentChildren(recNode, expression, initIndex + 1);
|
|
361
|
+
const lastPipeIndex = findLastPipeIndex(afterInit, expression);
|
|
362
|
+
if (lastPipeIndex < 0) {
|
|
363
|
+
return {
|
|
364
|
+
nodes: afterInit,
|
|
365
|
+
headerEndIndex: initIndex + 1
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return {
|
|
370
|
+
nodes: afterInit.slice(lastPipeIndex + 1),
|
|
371
|
+
headerEndIndex: recNode.children.indexOf(afterInit[lastPipeIndex]) + 1
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function contentChildren(generatorNode: AstNode, expression: string, fromIndex: number): AstNode[] {
|
|
376
|
+
return generatorNode.children.slice(fromIndex).filter(child => !isClosingBrace(child, expression));
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
function findDeclarativeDomain(declNode: AstNode, expression: string): AstNode | null {
|
|
380
|
+
const inIndex = declNode.children.findIndex(child => expression.slice(child.from, child.to) === '∈');
|
|
381
|
+
if (inIndex < 0) {
|
|
382
|
+
return null;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
for (let index = inIndex + 1; index < declNode.children.length; index++) {
|
|
386
|
+
const child = declNode.children[index];
|
|
387
|
+
if (isPipeToken(child, expression) || isClosingBrace(child, expression)) {
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
if (child.typeID === Setexpr) {
|
|
391
|
+
return child;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return null;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
function findImperativeTuple(impNode: AstNode): AstNode | null {
|
|
399
|
+
for (const child of impNode.children) {
|
|
400
|
+
if (child.typeID === Setexpr) {
|
|
401
|
+
return child;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function findLastPipeIndex(nodes: AstNode[], expression: string): number {
|
|
408
|
+
for (let index = nodes.length - 1; index >= 0; index--) {
|
|
409
|
+
if (isPipeToken(nodes[index], expression)) {
|
|
410
|
+
return index;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return -1;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function generatorHeaderIsValid(generatorNode: AstNode, expression: string, headerEndIndex: number): boolean {
|
|
417
|
+
for (let index = 0; index < headerEndIndex; index++) {
|
|
418
|
+
const child = generatorNode.children[index];
|
|
419
|
+
if (child.typeID === TokenID.ERROR) {
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
if (isStructuralGeneratorToken(child, expression)) {
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
if (subtreeHasError(child)) {
|
|
426
|
+
return false;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
return true;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function isIncompleteDeclarativeBody(slot: GeneratorBodySlot): boolean {
|
|
433
|
+
return isEmptyOrErrorOnlyBody(slot.nodes);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function isIncompleteImperativeBody(slot: GeneratorBodySlot, expression: string): boolean {
|
|
437
|
+
if (slot.nodes.length === 0) {
|
|
438
|
+
return true;
|
|
439
|
+
}
|
|
440
|
+
if (slot.nodes.length === 1 && slot.nodes[0].typeID === Imp_blocks) {
|
|
441
|
+
return isImpBlocksIncomplete(slot.nodes[0], expression);
|
|
442
|
+
}
|
|
443
|
+
return isEmptyOrErrorOnlyBody(slot.nodes);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
function isIncompleteRecursionBody(slot: GeneratorBodySlot): boolean {
|
|
447
|
+
return isEmptyOrErrorOnlyBody(slot.nodes);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function isEmptyOrErrorOnlyBody(nodes: AstNode[]): boolean {
|
|
451
|
+
if (nodes.length === 0) {
|
|
452
|
+
return true;
|
|
453
|
+
}
|
|
454
|
+
if (nodes.length === 1) {
|
|
455
|
+
return isErrorPlaceholder(nodes[0]);
|
|
456
|
+
}
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
function isImpBlocksIncomplete(blocksNode: AstNode, expression: string): boolean {
|
|
461
|
+
if (blocksNode.children.length === 0) {
|
|
462
|
+
return true;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const lastChild = blocksNode.children[blocksNode.children.length - 1];
|
|
466
|
+
if (lastChild.typeID === TokenID.ERROR) {
|
|
467
|
+
return true;
|
|
468
|
+
}
|
|
469
|
+
if (isSemicolonToken(lastChild, expression)) {
|
|
470
|
+
return true;
|
|
471
|
+
}
|
|
472
|
+
if (lastChild.typeID === Setexpr && isErrorPlaceholder(lastChild)) {
|
|
473
|
+
return true;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
return false;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function isErrorInBodySlot(errorNode: AstNode, slot: GeneratorBodySlot, generatorNode: AstNode): boolean {
|
|
480
|
+
if (slot.nodes.length === 0) {
|
|
481
|
+
const bodyStart = generatorNode.children[slot.headerEndIndex]?.from ?? generatorNode.from;
|
|
482
|
+
return errorNode.from >= bodyStart;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
for (const bodyNode of slot.nodes) {
|
|
486
|
+
if (errorNode === bodyNode || isDescendantOf(bodyNode, errorNode)) {
|
|
487
|
+
if (isErrorPlaceholder(bodyNode)) {
|
|
488
|
+
return true;
|
|
489
|
+
}
|
|
490
|
+
if (bodyNode.typeID === Imp_blocks && isImpBlocksTailError(bodyNode, errorNode)) {
|
|
491
|
+
return true;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
return false;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
function isImpBlocksTailError(blocksNode: AstNode, errorNode: AstNode): boolean {
|
|
500
|
+
const lastChild = blocksNode.children[blocksNode.children.length - 1];
|
|
501
|
+
return lastChild.typeID === TokenID.ERROR && (errorNode === lastChild || isDescendantOf(lastChild, errorNode));
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
function isErrorPlaceholder(node: AstNode): boolean {
|
|
505
|
+
if (node.typeID === TokenID.ERROR) {
|
|
506
|
+
return true;
|
|
507
|
+
}
|
|
508
|
+
if (node.children.length === 0) {
|
|
509
|
+
return false;
|
|
510
|
+
}
|
|
511
|
+
return node.children.every(child => isErrorPlaceholder(child));
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
function isDescendantOf(ancestor: AstNode, node: AstNode): boolean {
|
|
515
|
+
let current: AstNode | null = node.parent;
|
|
516
|
+
while (current !== null) {
|
|
517
|
+
if (current === ancestor) {
|
|
518
|
+
return true;
|
|
519
|
+
}
|
|
520
|
+
current = current.parent;
|
|
521
|
+
}
|
|
522
|
+
return false;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function findRecursionInit(recursionNode: AstNode, expression: string): AstNode | null {
|
|
526
|
+
const assignIndex = recursionNode.children.findIndex(child => expression.slice(child.from, child.to) === ':=');
|
|
527
|
+
if (assignIndex < 0) {
|
|
528
|
+
return null;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
for (let index = assignIndex + 1; index < recursionNode.children.length; index++) {
|
|
532
|
+
const child = recursionNode.children[index];
|
|
533
|
+
if (child.typeID === TokenID.ERROR) {
|
|
534
|
+
break;
|
|
535
|
+
}
|
|
536
|
+
if (isPipeToken(child, expression) || isClosingBrace(child, expression)) {
|
|
537
|
+
continue;
|
|
538
|
+
}
|
|
539
|
+
return child;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
return null;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
function incompleteGeneratorError(code: RSErrorCode, errorNode: AstNode): RSErrorDescription {
|
|
546
|
+
return {
|
|
547
|
+
code,
|
|
548
|
+
from: errorNode.from,
|
|
549
|
+
to: errorNode.to
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
function isIncompleteGeneratorBodyCode(code: RSErrorCode): boolean {
|
|
554
|
+
return (
|
|
555
|
+
code === RSErrorCode.expectedDeclarativeBody ||
|
|
556
|
+
code === RSErrorCode.expectedImperativeBody ||
|
|
557
|
+
code === RSErrorCode.expectedRecursiveBody
|
|
558
|
+
);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
function isPipeToken(node: AstNode, expression: string): boolean {
|
|
562
|
+
return expression.slice(node.from, node.to) === '|';
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
function isSemicolonToken(node: AstNode, expression: string): boolean {
|
|
566
|
+
return expression.slice(node.from, node.to) === ';';
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
function isClosingBrace(node: AstNode, expression: string): boolean {
|
|
570
|
+
return node.typeID !== TokenID.ERROR && expression.slice(node.from, node.to) === '}';
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
function isStructuralGeneratorToken(node: AstNode, expression: string): boolean {
|
|
574
|
+
const text = expression.slice(node.from, node.to);
|
|
575
|
+
return text === '{' || text === '}' || text === '|' || text === '∈' || text === ':=' || text === ';';
|
|
576
|
+
}
|
|
577
|
+
|
|
164
578
|
function subtreeHasError(node: AstNode): boolean {
|
|
165
579
|
if (node.typeID === TokenID.ERROR) {
|
|
166
580
|
return true;
|
|
@@ -257,6 +671,10 @@ function isFunctionDeclNode(node: AstNode): boolean {
|
|
|
257
671
|
return node.typeID === Function_decl || node.typeID === TokenID.NT_FUNC_DEFINITION;
|
|
258
672
|
}
|
|
259
673
|
|
|
674
|
+
function isQuantifierNode(node: AstNode): boolean {
|
|
675
|
+
return node.typeID === Logic_quantor;
|
|
676
|
+
}
|
|
677
|
+
|
|
260
678
|
function isFunctionNode(node: AstNode): boolean {
|
|
261
679
|
return node.typeID === Function || node.typeID === TokenID.ID_FUNCTION;
|
|
262
680
|
}
|