@rsconcept/domain 3.0.1 → 3.1.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-CzFaWR7w.d.ts → analyzer-B35QsI3L.d.ts} +2 -2
- package/dist/{ast-annotations-x4PJ_Lhc.d.ts → ast-annotations-DclU1Ser.d.ts} +2 -2
- package/dist/{calculator-uPaTV3hc.d.ts → calculator-B-1p712X.d.ts} +2 -2
- package/dist/{diagnostics-DKyMf6q-.d.ts → diagnostics-D4_B7rt2.d.ts} +3 -3
- package/dist/{error-B0EkIx4K.d.ts → error-S1JghCNN.d.ts} +30 -2
- package/dist/{index-CnuO4w8e.d.ts → index-D-w-bgei.d.ts} +4 -4
- package/dist/{index-DCO4mxiO.d.ts → index-DzvllU3P.d.ts} +4 -4
- package/dist/index.d.ts +6 -6
- package/dist/index.js +2 -2
- package/dist/library/diagnostics.d.ts +1 -1
- package/dist/library/index.d.ts +2 -2
- package/dist/library/oss-api.d.ts +1 -1
- package/dist/library/rsengine.d.ts +3 -3
- package/dist/library/rsform-api/index.d.ts +1 -1
- package/dist/library/rsform.d.ts +1 -1
- package/dist/library/rsmodel-api.d.ts +3 -3
- package/dist/library/rsmodel-api.js +16 -2
- package/dist/library/rsmodel-api.js.map +1 -1
- package/dist/library/rsmodel.d.ts +1 -1
- package/dist/library/structure-planner.d.ts +2 -2
- package/dist/rslang/ast-annotations.d.ts +1 -1
- package/dist/rslang/error.d.ts +2 -2
- package/dist/rslang/error.js +16 -1
- package/dist/rslang/error.js.map +1 -1
- package/dist/rslang/eval/calculator.d.ts +1 -1
- package/dist/rslang/eval/evaluator.d.ts +12 -2
- package/dist/rslang/eval/evaluator.js +37 -5
- package/dist/rslang/eval/evaluator.js.map +1 -1
- package/dist/rslang/index.d.ts +6 -6
- package/dist/rslang/index.js +2 -2
- package/dist/rslang/parser/syntax-errors/index.d.ts +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/index.ts +1 -1
- package/src/library/rsmodel-api.test.ts +79 -0
- package/src/library/rsmodel-api.ts +30 -2
- package/src/rslang/error.test.ts +23 -0
- package/src/rslang/error.ts +42 -0
- package/src/rslang/eval/evaluator.test.ts +56 -1
- package/src/rslang/eval/evaluator.ts +50 -7
- package/src/rslang/index.ts +1 -1
|
@@ -52,17 +52,49 @@ var Evaluator = class {
|
|
|
52
52
|
this.callSiteStack = [];
|
|
53
53
|
this.iterationCounter = 0;
|
|
54
54
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Surface highlight target in the root expression under evaluation.
|
|
57
|
+
* Nested call sites live in callee ASTs — only the outermost call is in the root.
|
|
58
|
+
*/
|
|
59
|
+
surfaceErrorNode(fault) {
|
|
60
|
+
return this.callSiteStack[0] ?? fault;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Builds innermost-first frames for called `F#`/`P#` bodies only.
|
|
64
|
+
* The root expression is represented by the surface `from`/`to`, not a stack frame.
|
|
65
|
+
* Returns `undefined` when the fault is in the root expression (no function call).
|
|
66
|
+
*/
|
|
67
|
+
buildEvalStack(fault) {
|
|
68
|
+
if (this.callSiteStack.length === 0) return;
|
|
69
|
+
const frames = [];
|
|
70
|
+
const innermostCall = this.callSiteStack[this.callSiteStack.length - 1];
|
|
71
|
+
if (!innermostCall) return;
|
|
72
|
+
frames.push({
|
|
73
|
+
alias: getNodeText(innermostCall.children[0]),
|
|
74
|
+
from: fault.from,
|
|
75
|
+
to: fault.to
|
|
76
|
+
});
|
|
77
|
+
for (let index = this.callSiteStack.length - 1; index >= 1; index--) {
|
|
78
|
+
const callSite = this.callSiteStack[index];
|
|
79
|
+
const outerCall = this.callSiteStack[index - 1];
|
|
80
|
+
if (!callSite || !outerCall) continue;
|
|
81
|
+
frames.push({
|
|
82
|
+
alias: getNodeText(outerCall.children[0]),
|
|
83
|
+
from: callSite.from,
|
|
84
|
+
to: callSite.to
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
return frames;
|
|
58
88
|
}
|
|
59
89
|
onError(code, node, params) {
|
|
60
|
-
const target = this.
|
|
90
|
+
const target = this.surfaceErrorNode(node);
|
|
91
|
+
const stack = this.buildEvalStack(node);
|
|
61
92
|
this.reporter?.({
|
|
62
93
|
code,
|
|
63
94
|
from: target.from,
|
|
64
95
|
to: target.to,
|
|
65
|
-
params
|
|
96
|
+
...params !== void 0 ? { params } : {},
|
|
97
|
+
...stack !== void 0 ? { stack } : {}
|
|
66
98
|
});
|
|
67
99
|
if (this.annotateErrors) annotateError(target, code, params);
|
|
68
100
|
return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"evaluator.js","names":[],"sources":["../../../src/rslang/eval/evaluator.ts"],"sourcesContent":["/**\n * Module: AST evaluation - visitor-pattern evaluator for RS expressions.\n */\n\nimport { type AstNode, getNodeIndices, getNodeText } from '../../parsing';\nimport { annotateError } from '../ast-annotations';\nimport { type ErrorReporter, RSErrorCode } from '../error';\nimport { labelRSLangNode } from '../labels';\nimport { TokenID } from '../parser/token';\n\nimport { EvaluationCache, EvaluationMetadata } from './evaluation-cache';\nimport {\n BOOL_INFINITY,\n CalcInvalidDataError,\n compare,\n EmptySetV,\n set,\n SET_INFINITY,\n tuple,\n type Value,\n VALUE_FALSE,\n VALUE_TRUE,\n type ValueContext\n} from './value';\nimport {\n boolean,\n cartesianProduct,\n contains,\n isSubsetOrEq,\n projection,\n reduce,\n setDiff,\n setIntersection,\n setSymDiff,\n setUnion\n} from './value-api';\n\n/** Maximum iterations to prevent infinite loops (recursion, quantifiers, etc.). */\nconst MAX_ITERATIONS = 1_000_000;\n\nconst TICK_PER_FUNCTION = 3;\nconst TICK_PER_RECURSION = 3;\nconst TICK_PER_IMPERATIVE = 1;\nconst TICK_PER_DECLARATIVE = 1;\nconst TICK_PER_QUANTIFIER = 1;\n\n/** AST context. */\nexport type ASTContext = Map<string, AstNode>;\n\n/** AST calculator - evaluates RS expressions via visitor pattern and provides updates via listeners.\n * Not safe for concurrent {@link run} calls on the same instance; use separate evaluators instead. */\nexport class Evaluator {\n private reporter?: ErrorReporter;\n private annotateErrors = false;\n private disableCache = false;\n private locals: LocalContext = new LocalContext();\n private nodeMetadata: EvaluationMetadata = new EvaluationMetadata();\n private evalCache: EvaluationCache = new EvaluationCache();\n private callSiteStack: AstNode[] = [];\n private context: ValueContext;\n private treeContext: ASTContext;\n\n public iterationCounter = 0;\n\n /** Cache hits in the current evaluation run (for tests/diagnostics). */\n public get cacheHits(): number {\n return this.evalCache.hits;\n }\n\n constructor(context: ValueContext, astContext: ASTContext) {\n this.treeContext = astContext;\n this.context = context;\n }\n\n public run(\n ast: AstNode,\n reporter?: ErrorReporter,\n annotateErrors: boolean = false,\n disableCache: boolean = false\n ): Value | null {\n if (ast.hasError) {\n return null;\n }\n this.reporter = reporter;\n this.annotateErrors = annotateErrors;\n this.disableCache = disableCache;\n this.clear();\n return this.dispatchVisit(ast);\n }\n\n private clear(): void {\n this.locals = new LocalContext();\n this.evalCache.clear();\n this.callSiteStack = [];\n this.iterationCounter = 0;\n }\n\n private errorNode(node: AstNode): AstNode {\n if (this.callSiteStack.length > 0) {\n return this.callSiteStack[this.callSiteStack.length - 1];\n }\n return node;\n }\n\n private onError(code: RSErrorCode, node: AstNode, params?: string[]): null {\n const target = this.errorNode(node);\n this.reporter?.({ code, from: target.from, to: target.to, params });\n if (this.annotateErrors) {\n annotateError(target, code, params);\n }\n return null;\n }\n\n private tick(node: AstNode, counter: number = 1): boolean {\n this.iterationCounter += counter;\n if (this.iterationCounter > MAX_ITERATIONS) {\n this.onError(RSErrorCode.iterationsLimit, node, [String(MAX_ITERATIONS)]);\n return false;\n }\n return true;\n }\n\n private dispatchDeclare(node: AstNode, value: Value): void {\n switch (node.typeID) {\n case TokenID.ID_LOCAL:\n return this.declareLocal(node, value);\n case TokenID.NT_TUPLE_DECL:\n return this.declareTuple(node, value as Value[]);\n case TokenID.NT_ARG_DECL:\n return this.dispatchDeclare(node.children[0], value);\n }\n }\n\n private declareLocal(node: AstNode, value: Value): void {\n const alias = getNodeText(node);\n this.locals.setLocal(alias, value);\n }\n\n private declareTuple(node: AstNode, value: Value[]): void {\n for (let child = 0; child < node.children.length; child++) {\n this.dispatchDeclare(node.children[child], value[child + 1]);\n }\n }\n\n private dispatchVisit(node: AstNode): Value | null {\n const info = this.nodeMetadata.get(node);\n let stamp: string | null = null;\n if (info.cacheable && !this.disableCache) {\n stamp = this.locals.buildDependencyStamp(info.reads);\n if (stamp !== null) {\n const cached = this.evalCache.lookup(info.structuralKey, stamp);\n if (cached !== undefined) {\n return cached;\n }\n }\n }\n\n try {\n const result = this.dispatchVisitImpl(node);\n if (!this.disableCache && result !== null && info.cacheable && stamp !== null) {\n this.evalCache.store(info.structuralKey, stamp, result);\n }\n return result;\n } catch (error) {\n if (error instanceof CalcInvalidDataError) {\n return this.onError(RSErrorCode.calcInvalidData, node, [error.left, error.right, labelRSLangNode(node)]);\n }\n this.onError(RSErrorCode.calcUnknownError, node);\n return null;\n }\n }\n\n private dispatchVisitImpl(node: AstNode): Value | null {\n switch (node.typeID) {\n case TokenID.ID_GLOBAL:\n return this.visitGlobal(node);\n\n case TokenID.NT_FUNC_CALL:\n return this.visitFunctionCall(node);\n\n case TokenID.ID_LOCAL:\n case TokenID.ID_RADICAL:\n return this.visitLocal(node);\n\n case TokenID.LIT_INTEGER:\n return this.visitInteger(node);\n\n case TokenID.LIT_WHOLE_NUMBERS:\n return this.onError(RSErrorCode.iterateInfinity, node);\n\n case TokenID.LIT_EMPTYSET:\n return EmptySetV;\n\n case TokenID.PLUS:\n case TokenID.MINUS:\n case TokenID.MULTIPLY:\n return this.visitArithmetic(node);\n\n case TokenID.CARD:\n return this.visitCard(node);\n\n case TokenID.QUANTOR_UNIVERSAL:\n case TokenID.QUANTOR_EXISTS:\n return this.visitQuantifier(node);\n\n case TokenID.LOGIC_NOT:\n return this.visitNegation(node);\n\n case TokenID.LOGIC_AND:\n case TokenID.LOGIC_OR:\n case TokenID.LOGIC_IMPLICATION:\n case TokenID.LOGIC_EQUIVALENT:\n return this.visitLogicBinary(node);\n\n case TokenID.EQUAL:\n case TokenID.NOTEQUAL:\n return this.visitEquals(node);\n\n case TokenID.GREATER:\n case TokenID.LESSER:\n case TokenID.GREATER_OR_EQ:\n case TokenID.LESSER_OR_EQ:\n return this.visitIntegerPredicate(node);\n\n case TokenID.SET_IN:\n case TokenID.SET_NOT_IN:\n case TokenID.SUBSET:\n case TokenID.SUBSET_OR_EQ:\n case TokenID.NOT_SUBSET:\n return this.visitSetexprPredicate(node);\n\n case TokenID.DECART:\n return this.visitDecart(node);\n\n case TokenID.BOOLEAN:\n return this.visitBoolean(node);\n\n case TokenID.NT_TUPLE:\n return this.visitTuple(node);\n\n case TokenID.NT_ENUMERATION:\n return this.visitEnumeration(node);\n\n case TokenID.BOOL:\n return this.visitBool(node);\n\n case TokenID.DEBOOL:\n return this.visitDebool(node);\n\n case TokenID.SET_UNION:\n case TokenID.SET_INTERSECTION:\n case TokenID.SET_MINUS:\n case TokenID.SET_SYMMETRIC_MINUS:\n return this.visitSetexprBinary(node);\n\n case TokenID.BIGPR:\n return this.visitProjectSet(node);\n\n case TokenID.SMALLPR:\n return this.visitProjectTuple(node);\n\n case TokenID.FILTER:\n return this.visitFilter(node);\n\n case TokenID.REDUCE:\n return this.visitReduce(node);\n\n case TokenID.NT_DECLARATIVE_EXPR:\n return this.visitDeclarative(node);\n\n case TokenID.NT_IMPERATIVE_EXPR:\n return this.visitImperative(node);\n\n case TokenID.ASSIGN:\n return this.visitAssign(node);\n\n case TokenID.NT_RECURSIVE_FULL:\n case TokenID.NT_RECURSIVE_SHORT:\n return this.visitRecursion(node);\n\n case TokenID.NT_FUNC_DEFINITION:\n return this.onError(RSErrorCode.calculationNotSupported, node);\n }\n return null;\n }\n\n private visitChild(node: AstNode, index: number): Value | null {\n return this.dispatchVisit(node.children[index]);\n }\n\n private visitGlobal(node: AstNode): Value | null {\n const alias = getNodeText(node);\n const value = this.context.get(alias) ?? null;\n if (value === null) {\n return this.onError(RSErrorCode.calcGlobalMissing, node, [alias]);\n }\n return value;\n }\n\n private visitLocal(node: AstNode): Value | null {\n const alias = getNodeText(node);\n const value = this.locals.findLocal(alias);\n if (value === null) {\n return this.onError(RSErrorCode.localUndeclared, node, [alias]);\n }\n return value;\n }\n\n private visitFunctionCall(node: AstNode): Value | null {\n const funcName = getNodeText(node.children[0]);\n const ast = this.treeContext.get(funcName);\n if (!ast) {\n return this.onError(RSErrorCode.calcGlobalMissing, node.children[0], [funcName]);\n }\n if (!this.tick(node, TICK_PER_FUNCTION)) {\n return null;\n }\n\n const args: Value[] = [];\n for (let i = 1; i < node.children.length; i++) {\n const arg = this.visitChild(node, i);\n if (arg === null) {\n return null;\n }\n args.push(arg);\n }\n\n this.locals.startScope();\n for (let i = 0; i < args.length; i++) {\n this.dispatchDeclare(ast.children[0].children[i], args[i]);\n }\n this.callSiteStack.push(node);\n let result: Value | null;\n try {\n result = this.visitChild(ast, 1);\n } finally {\n this.callSiteStack.pop();\n }\n this.locals.endScope();\n return result;\n }\n\n private visitInteger(node: AstNode): Value | null {\n const value = node.data.dataType === 'number' ? (node.data.value as number) : Number(node.data.value);\n return Math.floor(value);\n }\n\n private visitArithmetic(node: AstNode): Value | null {\n const v1 = this.visitChild(node, 0);\n const v2 = this.visitChild(node, 1);\n if (v1 === null || v2 === null) {\n return null;\n }\n const a = v1 as number;\n const b = v2 as number;\n switch (node.typeID) {\n case TokenID.PLUS:\n return a + b;\n case TokenID.MINUS:\n return a - b;\n case TokenID.MULTIPLY:\n return a * b;\n }\n return null;\n }\n\n private visitCard(node: AstNode): Value | null {\n const base = this.visitChild(node, 0);\n if (base === null || !Array.isArray(base)) {\n return null;\n }\n return base.length;\n }\n\n private visitQuantifier(node: AstNode): Value | null {\n const domain = this.visitChild(node, 1) as Value[];\n if (domain === null) {\n return null;\n }\n const isUniversal = node.typeID === TokenID.QUANTOR_UNIVERSAL;\n if (domain.length === 0) {\n return isUniversal ? VALUE_TRUE : VALUE_FALSE;\n }\n\n const varNodes = node.children[0].typeID === TokenID.NT_ENUM_DECL ? node.children[0].children : [node.children[0]];\n const count = domain.length;\n const iterators: number[] = [];\n for (const declaration of varNodes) {\n iterators.push(0);\n this.dispatchDeclare(declaration, domain[0]);\n }\n let finishIteration = false;\n while (!finishIteration) {\n const iterationValue = this.visitChild(node, 2);\n if (iterationValue === null) {\n return null;\n }\n if ((iterationValue === VALUE_TRUE) !== isUniversal) {\n return !isUniversal ? VALUE_TRUE : VALUE_FALSE;\n }\n let incrementIndex = iterators.length - 1;\n while (true) {\n if (iterators[incrementIndex] < count - 1) {\n iterators[incrementIndex]++;\n if (!this.tick(node, TICK_PER_QUANTIFIER)) {\n return null;\n }\n this.dispatchDeclare(varNodes[incrementIndex], domain[iterators[incrementIndex]]);\n incrementIndex = iterators.length - 1;\n break;\n } else if (incrementIndex === 0) {\n finishIteration = true;\n break;\n } else {\n iterators[incrementIndex] = 0;\n this.dispatchDeclare(varNodes[incrementIndex], domain[0]);\n incrementIndex--;\n }\n }\n }\n return isUniversal ? VALUE_TRUE : VALUE_FALSE;\n }\n\n private visitNegation(node: AstNode): Value | null {\n const value = this.visitChild(node, 0);\n if (value === null) {\n return null;\n }\n return (value as number) === VALUE_TRUE ? VALUE_FALSE : VALUE_TRUE;\n }\n\n private tryEvaluateFromFirstArg(op: number, first: boolean): Value | null {\n if ((op === TokenID.LOGIC_AND && !first) || (op === TokenID.LOGIC_OR && first)) {\n return first ? VALUE_TRUE : VALUE_FALSE;\n }\n if (op === TokenID.LOGIC_IMPLICATION && !first) {\n return VALUE_TRUE;\n }\n return null;\n }\n\n private visitLogicBinary(node: AstNode): Value | null {\n const v1 = this.visitChild(node, 0);\n if (v1 === null) {\n return null;\n }\n const b1 = v1 === VALUE_TRUE;\n const attempt = this.tryEvaluateFromFirstArg(node.typeID, b1);\n if (attempt !== null) {\n return attempt;\n }\n\n const v2 = this.visitChild(node, 1);\n if (v2 === null) {\n return null;\n }\n const b2 = v2 === VALUE_TRUE;\n let result: boolean;\n switch (node.typeID) {\n case TokenID.LOGIC_AND:\n result = b1 && b2;\n break;\n case TokenID.LOGIC_OR:\n result = b1 || b2;\n break;\n case TokenID.LOGIC_IMPLICATION:\n result = !b1 || b2;\n break;\n case TokenID.LOGIC_EQUIVALENT:\n result = b1 === b2;\n break;\n default:\n return null;\n }\n return result ? VALUE_TRUE : VALUE_FALSE;\n }\n\n private visitEquals(node: AstNode): Value | null {\n const v1 = this.visitChild(node, 0);\n if (v1 === null) {\n return null;\n }\n const v2 = this.visitChild(node, 1);\n if (v2 === null) {\n return null;\n }\n const areEqual = compare(v1, v2) === 0;\n return areEqual === (node.typeID !== TokenID.NOTEQUAL) ? VALUE_TRUE : VALUE_FALSE;\n }\n\n private visitIntegerPredicate(node: AstNode): Value | null {\n const v1 = this.visitChild(node, 0);\n if (v1 === null) {\n return null;\n }\n const v2 = this.visitChild(node, 1);\n if (v2 === null) {\n return null;\n }\n const a = v1 as number;\n const b = v2 as number;\n let result: boolean;\n switch (node.typeID) {\n case TokenID.GREATER:\n result = a > b;\n break;\n case TokenID.LESSER:\n result = a < b;\n break;\n case TokenID.GREATER_OR_EQ:\n result = a >= b;\n break;\n case TokenID.LESSER_OR_EQ:\n result = a <= b;\n break;\n default:\n return null;\n }\n return result ? VALUE_TRUE : VALUE_FALSE;\n }\n\n private visitSetexprPredicate(node: AstNode): Value | null {\n const v1 = this.visitChild(node, 0);\n if (v1 === null) {\n return null;\n }\n const v2 = this.visitChild(node, 1);\n if (v2 === null) {\n return null;\n }\n let result: boolean;\n switch (node.typeID) {\n case TokenID.SET_IN:\n result = contains(v2 as Value[], v1);\n break;\n case TokenID.SET_NOT_IN:\n result = !contains(v2 as Value[], v1);\n break;\n case TokenID.SUBSET:\n result = compare(v1, v2) !== 0 && isSubsetOrEq(v1 as Value[], v2 as Value[]);\n break;\n case TokenID.NOT_SUBSET:\n result = compare(v1, v2) === 0 || !isSubsetOrEq(v1 as Value[], v2 as Value[]);\n break;\n case TokenID.SUBSET_OR_EQ:\n result = isSubsetOrEq(v1 as Value[], v2 as Value[]);\n break;\n default:\n return null;\n }\n return result ? VALUE_TRUE : VALUE_FALSE;\n }\n\n private visitDecart(node: AstNode): Value | null {\n const args: Value[] = [];\n for (let i = 0; i < node.children.length; i++) {\n const component = this.visitChild(node, i) as Value[];\n if (component === null) {\n return null;\n }\n if (component.length === 0) {\n return EmptySetV;\n }\n args.push(component);\n }\n const result = cartesianProduct(args as Value[][]);\n if (result === null) {\n this.onError(RSErrorCode.setOverflow, node, [String(SET_INFINITY)]);\n return null;\n }\n return result;\n }\n\n private visitBoolean(node: AstNode): Value | null {\n const base = this.visitChild(node, 0) as Value[];\n if (base === null) {\n return null;\n }\n const result = boolean(base);\n if (result === null) {\n this.onError(RSErrorCode.booleanBaseLimit, node.children[0], [String(BOOL_INFINITY)]);\n return null;\n }\n return result;\n }\n\n private visitTuple(node: AstNode): Value | null {\n const args: Value[] = [];\n for (let i = 0; i < node.children.length; i++) {\n const component = this.visitChild(node, i);\n if (component === null) {\n return null;\n }\n args.push(component);\n }\n return tuple(args);\n }\n\n private visitEnumeration(node: AstNode): Value | null {\n const args: Value[] = [];\n for (let i = 0; i < node.children.length; i++) {\n const element = this.visitChild(node, i);\n if (element === null) {\n return null;\n }\n args.push(element);\n }\n return set(args);\n }\n\n private visitBool(node: AstNode): Value | null {\n const element = this.visitChild(node, 0);\n if (element === null) {\n return null;\n }\n return [element];\n }\n\n private visitDebool(node: AstNode): Value | null {\n const target = this.visitChild(node, 0) as Value[];\n if (target === null) {\n return null;\n }\n if (target.length !== 1) {\n return this.onError(RSErrorCode.calcInvalidDebool, node.children[0]);\n }\n return target[0];\n }\n\n private visitSetexprBinary(node: AstNode): Value | null {\n const v1 = this.visitChild(node, 0);\n if (v1 === null) {\n return null;\n }\n const v2 = this.visitChild(node, 1);\n if (v2 === null) {\n return null;\n }\n switch (node.typeID) {\n case TokenID.SET_UNION:\n return setUnion(v1 as Value[], v2 as Value[]);\n case TokenID.SET_INTERSECTION:\n return setIntersection(v1 as Value[], v2 as Value[]);\n case TokenID.SET_MINUS:\n return setDiff(v1 as Value[], v2 as Value[]);\n case TokenID.SET_SYMMETRIC_MINUS:\n return setSymDiff(v1 as Value[], v2 as Value[]);\n }\n return null;\n }\n\n private visitProjectSet(node: AstNode): Value | null {\n const target = this.visitChild(node, 0);\n if (target === null) {\n return null;\n }\n const indices = getNodeIndices(node);\n return projection(target as Value[][], indices);\n }\n\n private visitProjectTuple(node: AstNode): Value | null {\n const target = this.visitChild(node, 0) as Value[];\n if (target === null) {\n return null;\n }\n const indices = getNodeIndices(node);\n const components = indices.map(i => target[i]);\n return components.length === 1 ? components[0] : tuple(components);\n }\n\n private visitFilter(node: AstNode): Value | null {\n const lastIdx = node.children.length - 1;\n const argVal = this.visitChild(node, lastIdx) as Value[][];\n if (argVal === null) {\n return null;\n }\n if (argVal.length === 0) {\n return EmptySetV;\n }\n\n const indices = getNodeIndices(node);\n const tupleParam = indices.length === lastIdx;\n if (tupleParam) {\n const params: Value[] = [];\n for (let i = 0; i < lastIdx; i++) {\n const param = this.visitChild(node, i) as Value[];\n if (param === null) {\n return null;\n }\n if (param.length === 0) {\n return EmptySetV;\n }\n params.push(param);\n }\n const result: Value[] = [];\n for (const element of argVal) {\n let valid = true;\n for (let j = 0; j < indices.length; j++) {\n const comp = element[indices[j]];\n const paramSet = params[j] as Value[];\n if (!contains(paramSet, comp)) {\n valid = false;\n break;\n }\n }\n if (valid) {\n result.push(element);\n }\n }\n return result;\n } else {\n const paramVal = this.visitChild(node, 0) as Value[];\n if (paramVal === null) {\n return null;\n }\n if (paramVal.length === 0) {\n return EmptySetV;\n }\n\n const result: Value[] = [];\n for (const element of argVal) {\n const comps = indices.map(i => element[i]);\n const testElement = comps.length === 1 ? comps[0] : tuple(comps);\n if (contains(paramVal, testElement)) result.push(element);\n }\n return result;\n }\n }\n\n private visitReduce(node: AstNode): Value | null {\n const target = this.visitChild(node, 0);\n if (target === null) {\n return null;\n }\n return reduce(target as Value[][]);\n }\n\n private visitDeclarative(node: AstNode): Value | null {\n const domain = this.visitChild(node, 1);\n if (domain === null) {\n return null;\n }\n\n const elements = [];\n for (const element of domain as Value[]) {\n if (!this.tick(node, TICK_PER_DECLARATIVE)) {\n return null;\n }\n this.dispatchDeclare(node.children[0], element);\n const value = this.visitChild(node, 2);\n if (value === null) {\n return null;\n }\n if (value === VALUE_TRUE) {\n elements.push(element);\n }\n }\n return elements.length === 0 ? EmptySetV : elements;\n }\n\n private visitImperative(node: AstNode): Value | null {\n const result: Value[] = [];\n const frames: IterationFrame[] = [];\n\n let currentChild = 1;\n\n // Advance to next iteration\n const advanceIterator = (): boolean => {\n while (frames.length > 0) {\n const top = frames[frames.length - 1];\n if (top.valueID < top.domain.length - 1) {\n top.valueID++;\n const nextValue = top.domain[top.valueID];\n if (!this.tick(node.children[top.childID], TICK_PER_IMPERATIVE)) {\n return false;\n }\n this.dispatchDeclare(node.children[top.childID].children[0], nextValue);\n currentChild = top.childID + 1;\n return true;\n }\n frames.pop();\n }\n return false;\n };\n\n while (true) {\n // Iteration end - create element and pop up stack\n if (currentChild >= node.children.length) {\n const element = this.visitChild(node, 0);\n if (element === null) {\n return null;\n }\n result.push(element);\n if (!advanceIterator()) {\n break;\n }\n continue;\n }\n\n // Iteration node\n const child = node.children[currentChild];\n if (child.typeID === TokenID.ITERATE) {\n const domain = this.visitChild(child, 1) as Value[];\n if (domain === null) {\n return null;\n }\n if (domain.length === 0) {\n if (!advanceIterator()) {\n break;\n }\n continue;\n }\n if (!this.tick(child, TICK_PER_IMPERATIVE)) {\n return null;\n }\n frames.push({\n childID: currentChild,\n domain,\n valueID: 0\n });\n this.dispatchDeclare(child.children[0], domain[0]);\n currentChild++;\n continue;\n }\n\n // Guard expression\n const value = this.dispatchVisit(child);\n if (value === null) {\n return null;\n }\n if (value === VALUE_FALSE) {\n if (!advanceIterator()) {\n break;\n }\n continue;\n }\n currentChild++;\n }\n return set(result);\n }\n\n private visitAssign(node: AstNode): Value | null {\n const value = this.visitChild(node, 1);\n if (value === null) {\n return null;\n }\n this.dispatchDeclare(node.children[0], value);\n return VALUE_TRUE;\n }\n\n private visitRecursion(node: AstNode): Value | null {\n const initialValue = this.visitChild(node, 1);\n if (initialValue === null) {\n return null;\n }\n const bodyIndex = node.typeID === TokenID.NT_RECURSIVE_FULL ? 3 : 2;\n let current: Value = initialValue;\n while (true) {\n if (!this.tick(node, TICK_PER_RECURSION)) {\n return null;\n }\n\n this.dispatchDeclare(node.children[0], current);\n if (node.typeID === TokenID.NT_RECURSIVE_FULL) {\n const pred = this.visitChild(node, 2);\n if (pred === null) {\n return null;\n }\n if (pred !== VALUE_TRUE) {\n break;\n }\n }\n\n const next = this.visitChild(node, bodyIndex);\n if (next === null) {\n return null;\n }\n if (compare(current, next) === 0) {\n break;\n }\n current = next;\n }\n\n return current;\n }\n}\n\n/** Imperative iteration block data. */\ninterface IterationFrame {\n childID: number;\n domain: Value[];\n valueID: number;\n}\n\n/** Local variable binding with version for cache invalidation. */\ninterface LocalBinding {\n id: number;\n version: number;\n value: Value;\n}\n\n/** Local variables context. */\nclass LocalContext {\n private nextBindingId = 1;\n private data = new Map<string, LocalBinding>();\n private callStack: Map<string, LocalBinding>[] = [];\n\n startScope(): void {\n this.callStack.push(this.data);\n this.data = new Map();\n }\n\n endScope(): void {\n this.data = this.callStack.pop()!;\n }\n\n setLocal(alias: string, value: Value): void {\n const existing = this.data.get(alias);\n if (existing) {\n existing.value = value;\n existing.version++;\n } else {\n this.data.set(alias, { id: this.nextBindingId++, version: 0, value });\n }\n }\n\n findLocal(alias: string): Value | null {\n return this.data.get(alias)?.value ?? null;\n }\n\n buildDependencyStamp(reads: ReadonlySet<string>): string | null {\n if (reads.size === 0) {\n return '';\n }\n const parts: string[] = [];\n for (const alias of [...reads].sort()) {\n const binding = this.data.get(alias);\n if (binding === undefined) {\n return null;\n }\n parts.push(`${binding.id}:${binding.version}`);\n }\n return parts.join('|');\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"evaluator.js","names":[],"sources":["../../../src/rslang/eval/evaluator.ts"],"sourcesContent":["/**\n * Module: AST evaluation - visitor-pattern evaluator for RS expressions.\n */\n\nimport { type AstNode, getNodeIndices, getNodeText } from '../../parsing';\nimport { annotateError } from '../ast-annotations';\nimport { type ErrorReporter, type EvalStackFrame, RSErrorCode } from '../error';\nimport { labelRSLangNode } from '../labels';\nimport { TokenID } from '../parser/token';\n\nimport { EvaluationCache, EvaluationMetadata } from './evaluation-cache';\nimport {\n BOOL_INFINITY,\n CalcInvalidDataError,\n compare,\n EmptySetV,\n set,\n SET_INFINITY,\n tuple,\n type Value,\n VALUE_FALSE,\n VALUE_TRUE,\n type ValueContext\n} from './value';\nimport {\n boolean,\n cartesianProduct,\n contains,\n isSubsetOrEq,\n projection,\n reduce,\n setDiff,\n setIntersection,\n setSymDiff,\n setUnion\n} from './value-api';\n\n/** Maximum iterations to prevent infinite loops (recursion, quantifiers, etc.). */\nconst MAX_ITERATIONS = 1_000_000;\n\nconst TICK_PER_FUNCTION = 3;\nconst TICK_PER_RECURSION = 3;\nconst TICK_PER_IMPERATIVE = 1;\nconst TICK_PER_DECLARATIVE = 1;\nconst TICK_PER_QUANTIFIER = 1;\n\n/** AST context. */\nexport type ASTContext = Map<string, AstNode>;\n\n/** AST calculator - evaluates RS expressions via visitor pattern and provides updates via listeners.\n * Not safe for concurrent {@link run} calls on the same instance; use separate evaluators instead. */\nexport class Evaluator {\n private reporter?: ErrorReporter;\n private annotateErrors = false;\n private disableCache = false;\n private locals: LocalContext = new LocalContext();\n private nodeMetadata: EvaluationMetadata = new EvaluationMetadata();\n private evalCache: EvaluationCache = new EvaluationCache();\n private callSiteStack: AstNode[] = [];\n private context: ValueContext;\n private treeContext: ASTContext;\n\n public iterationCounter = 0;\n\n /** Cache hits in the current evaluation run (for tests/diagnostics). */\n public get cacheHits(): number {\n return this.evalCache.hits;\n }\n\n constructor(context: ValueContext, astContext: ASTContext) {\n this.treeContext = astContext;\n this.context = context;\n }\n\n public run(\n ast: AstNode,\n reporter?: ErrorReporter,\n annotateErrors: boolean = false,\n disableCache: boolean = false\n ): Value | null {\n if (ast.hasError) {\n return null;\n }\n this.reporter = reporter;\n this.annotateErrors = annotateErrors;\n this.disableCache = disableCache;\n this.clear();\n return this.dispatchVisit(ast);\n }\n\n private clear(): void {\n this.locals = new LocalContext();\n this.evalCache.clear();\n this.callSiteStack = [];\n this.iterationCounter = 0;\n }\n\n /**\n * Surface highlight target in the root expression under evaluation.\n * Nested call sites live in callee ASTs — only the outermost call is in the root.\n */\n private surfaceErrorNode(fault: AstNode): AstNode {\n return this.callSiteStack[0] ?? fault;\n }\n\n /**\n * Builds innermost-first frames for called `F#`/`P#` bodies only.\n * The root expression is represented by the surface `from`/`to`, not a stack frame.\n * Returns `undefined` when the fault is in the root expression (no function call).\n */\n private buildEvalStack(fault: AstNode): readonly EvalStackFrame[] | undefined {\n if (this.callSiteStack.length === 0) {\n return undefined;\n }\n const frames: EvalStackFrame[] = [];\n const innermostCall = this.callSiteStack[this.callSiteStack.length - 1];\n if (!innermostCall) {\n return undefined;\n }\n frames.push({\n alias: getNodeText(innermostCall.children[0]),\n from: fault.from,\n to: fault.to\n });\n // Call sites at index ≥ 1 live in a callee body; index 0 is the root call site.\n for (let index = this.callSiteStack.length - 1; index >= 1; index--) {\n const callSite = this.callSiteStack[index];\n const outerCall = this.callSiteStack[index - 1];\n if (!callSite || !outerCall) {\n continue;\n }\n frames.push({\n alias: getNodeText(outerCall.children[0]),\n from: callSite.from,\n to: callSite.to\n });\n }\n return frames;\n }\n\n private onError(code: RSErrorCode, node: AstNode, params?: string[]): null {\n const target = this.surfaceErrorNode(node);\n const stack = this.buildEvalStack(node);\n this.reporter?.({\n code,\n from: target.from,\n to: target.to,\n ...(params !== undefined ? { params } : {}),\n ...(stack !== undefined ? { stack } : {})\n });\n if (this.annotateErrors) {\n annotateError(target, code, params);\n }\n return null;\n }\n\n private tick(node: AstNode, counter: number = 1): boolean {\n this.iterationCounter += counter;\n if (this.iterationCounter > MAX_ITERATIONS) {\n this.onError(RSErrorCode.iterationsLimit, node, [String(MAX_ITERATIONS)]);\n return false;\n }\n return true;\n }\n\n private dispatchDeclare(node: AstNode, value: Value): void {\n switch (node.typeID) {\n case TokenID.ID_LOCAL:\n return this.declareLocal(node, value);\n case TokenID.NT_TUPLE_DECL:\n return this.declareTuple(node, value as Value[]);\n case TokenID.NT_ARG_DECL:\n return this.dispatchDeclare(node.children[0], value);\n }\n }\n\n private declareLocal(node: AstNode, value: Value): void {\n const alias = getNodeText(node);\n this.locals.setLocal(alias, value);\n }\n\n private declareTuple(node: AstNode, value: Value[]): void {\n for (let child = 0; child < node.children.length; child++) {\n this.dispatchDeclare(node.children[child], value[child + 1]);\n }\n }\n\n private dispatchVisit(node: AstNode): Value | null {\n const info = this.nodeMetadata.get(node);\n let stamp: string | null = null;\n if (info.cacheable && !this.disableCache) {\n stamp = this.locals.buildDependencyStamp(info.reads);\n if (stamp !== null) {\n const cached = this.evalCache.lookup(info.structuralKey, stamp);\n if (cached !== undefined) {\n return cached;\n }\n }\n }\n\n try {\n const result = this.dispatchVisitImpl(node);\n if (!this.disableCache && result !== null && info.cacheable && stamp !== null) {\n this.evalCache.store(info.structuralKey, stamp, result);\n }\n return result;\n } catch (error) {\n if (error instanceof CalcInvalidDataError) {\n return this.onError(RSErrorCode.calcInvalidData, node, [error.left, error.right, labelRSLangNode(node)]);\n }\n this.onError(RSErrorCode.calcUnknownError, node);\n return null;\n }\n }\n\n private dispatchVisitImpl(node: AstNode): Value | null {\n switch (node.typeID) {\n case TokenID.ID_GLOBAL:\n return this.visitGlobal(node);\n\n case TokenID.NT_FUNC_CALL:\n return this.visitFunctionCall(node);\n\n case TokenID.ID_LOCAL:\n case TokenID.ID_RADICAL:\n return this.visitLocal(node);\n\n case TokenID.LIT_INTEGER:\n return this.visitInteger(node);\n\n case TokenID.LIT_WHOLE_NUMBERS:\n return this.onError(RSErrorCode.iterateInfinity, node);\n\n case TokenID.LIT_EMPTYSET:\n return EmptySetV;\n\n case TokenID.PLUS:\n case TokenID.MINUS:\n case TokenID.MULTIPLY:\n return this.visitArithmetic(node);\n\n case TokenID.CARD:\n return this.visitCard(node);\n\n case TokenID.QUANTOR_UNIVERSAL:\n case TokenID.QUANTOR_EXISTS:\n return this.visitQuantifier(node);\n\n case TokenID.LOGIC_NOT:\n return this.visitNegation(node);\n\n case TokenID.LOGIC_AND:\n case TokenID.LOGIC_OR:\n case TokenID.LOGIC_IMPLICATION:\n case TokenID.LOGIC_EQUIVALENT:\n return this.visitLogicBinary(node);\n\n case TokenID.EQUAL:\n case TokenID.NOTEQUAL:\n return this.visitEquals(node);\n\n case TokenID.GREATER:\n case TokenID.LESSER:\n case TokenID.GREATER_OR_EQ:\n case TokenID.LESSER_OR_EQ:\n return this.visitIntegerPredicate(node);\n\n case TokenID.SET_IN:\n case TokenID.SET_NOT_IN:\n case TokenID.SUBSET:\n case TokenID.SUBSET_OR_EQ:\n case TokenID.NOT_SUBSET:\n return this.visitSetexprPredicate(node);\n\n case TokenID.DECART:\n return this.visitDecart(node);\n\n case TokenID.BOOLEAN:\n return this.visitBoolean(node);\n\n case TokenID.NT_TUPLE:\n return this.visitTuple(node);\n\n case TokenID.NT_ENUMERATION:\n return this.visitEnumeration(node);\n\n case TokenID.BOOL:\n return this.visitBool(node);\n\n case TokenID.DEBOOL:\n return this.visitDebool(node);\n\n case TokenID.SET_UNION:\n case TokenID.SET_INTERSECTION:\n case TokenID.SET_MINUS:\n case TokenID.SET_SYMMETRIC_MINUS:\n return this.visitSetexprBinary(node);\n\n case TokenID.BIGPR:\n return this.visitProjectSet(node);\n\n case TokenID.SMALLPR:\n return this.visitProjectTuple(node);\n\n case TokenID.FILTER:\n return this.visitFilter(node);\n\n case TokenID.REDUCE:\n return this.visitReduce(node);\n\n case TokenID.NT_DECLARATIVE_EXPR:\n return this.visitDeclarative(node);\n\n case TokenID.NT_IMPERATIVE_EXPR:\n return this.visitImperative(node);\n\n case TokenID.ASSIGN:\n return this.visitAssign(node);\n\n case TokenID.NT_RECURSIVE_FULL:\n case TokenID.NT_RECURSIVE_SHORT:\n return this.visitRecursion(node);\n\n case TokenID.NT_FUNC_DEFINITION:\n return this.onError(RSErrorCode.calculationNotSupported, node);\n }\n return null;\n }\n\n private visitChild(node: AstNode, index: number): Value | null {\n return this.dispatchVisit(node.children[index]);\n }\n\n private visitGlobal(node: AstNode): Value | null {\n const alias = getNodeText(node);\n const value = this.context.get(alias) ?? null;\n if (value === null) {\n return this.onError(RSErrorCode.calcGlobalMissing, node, [alias]);\n }\n return value;\n }\n\n private visitLocal(node: AstNode): Value | null {\n const alias = getNodeText(node);\n const value = this.locals.findLocal(alias);\n if (value === null) {\n return this.onError(RSErrorCode.localUndeclared, node, [alias]);\n }\n return value;\n }\n\n private visitFunctionCall(node: AstNode): Value | null {\n const funcName = getNodeText(node.children[0]);\n const ast = this.treeContext.get(funcName);\n if (!ast) {\n return this.onError(RSErrorCode.calcGlobalMissing, node.children[0], [funcName]);\n }\n if (!this.tick(node, TICK_PER_FUNCTION)) {\n return null;\n }\n\n const args: Value[] = [];\n for (let i = 1; i < node.children.length; i++) {\n const arg = this.visitChild(node, i);\n if (arg === null) {\n return null;\n }\n args.push(arg);\n }\n\n this.locals.startScope();\n for (let i = 0; i < args.length; i++) {\n this.dispatchDeclare(ast.children[0].children[i], args[i]);\n }\n this.callSiteStack.push(node);\n let result: Value | null;\n try {\n result = this.visitChild(ast, 1);\n } finally {\n this.callSiteStack.pop();\n }\n this.locals.endScope();\n return result;\n }\n\n private visitInteger(node: AstNode): Value | null {\n const value = node.data.dataType === 'number' ? (node.data.value as number) : Number(node.data.value);\n return Math.floor(value);\n }\n\n private visitArithmetic(node: AstNode): Value | null {\n const v1 = this.visitChild(node, 0);\n const v2 = this.visitChild(node, 1);\n if (v1 === null || v2 === null) {\n return null;\n }\n const a = v1 as number;\n const b = v2 as number;\n switch (node.typeID) {\n case TokenID.PLUS:\n return a + b;\n case TokenID.MINUS:\n return a - b;\n case TokenID.MULTIPLY:\n return a * b;\n }\n return null;\n }\n\n private visitCard(node: AstNode): Value | null {\n const base = this.visitChild(node, 0);\n if (base === null || !Array.isArray(base)) {\n return null;\n }\n return base.length;\n }\n\n private visitQuantifier(node: AstNode): Value | null {\n const domain = this.visitChild(node, 1) as Value[];\n if (domain === null) {\n return null;\n }\n const isUniversal = node.typeID === TokenID.QUANTOR_UNIVERSAL;\n if (domain.length === 0) {\n return isUniversal ? VALUE_TRUE : VALUE_FALSE;\n }\n\n const varNodes = node.children[0].typeID === TokenID.NT_ENUM_DECL ? node.children[0].children : [node.children[0]];\n const count = domain.length;\n const iterators: number[] = [];\n for (const declaration of varNodes) {\n iterators.push(0);\n this.dispatchDeclare(declaration, domain[0]);\n }\n let finishIteration = false;\n while (!finishIteration) {\n const iterationValue = this.visitChild(node, 2);\n if (iterationValue === null) {\n return null;\n }\n if ((iterationValue === VALUE_TRUE) !== isUniversal) {\n return !isUniversal ? VALUE_TRUE : VALUE_FALSE;\n }\n let incrementIndex = iterators.length - 1;\n while (true) {\n if (iterators[incrementIndex] < count - 1) {\n iterators[incrementIndex]++;\n if (!this.tick(node, TICK_PER_QUANTIFIER)) {\n return null;\n }\n this.dispatchDeclare(varNodes[incrementIndex], domain[iterators[incrementIndex]]);\n incrementIndex = iterators.length - 1;\n break;\n } else if (incrementIndex === 0) {\n finishIteration = true;\n break;\n } else {\n iterators[incrementIndex] = 0;\n this.dispatchDeclare(varNodes[incrementIndex], domain[0]);\n incrementIndex--;\n }\n }\n }\n return isUniversal ? VALUE_TRUE : VALUE_FALSE;\n }\n\n private visitNegation(node: AstNode): Value | null {\n const value = this.visitChild(node, 0);\n if (value === null) {\n return null;\n }\n return (value as number) === VALUE_TRUE ? VALUE_FALSE : VALUE_TRUE;\n }\n\n private tryEvaluateFromFirstArg(op: number, first: boolean): Value | null {\n if ((op === TokenID.LOGIC_AND && !first) || (op === TokenID.LOGIC_OR && first)) {\n return first ? VALUE_TRUE : VALUE_FALSE;\n }\n if (op === TokenID.LOGIC_IMPLICATION && !first) {\n return VALUE_TRUE;\n }\n return null;\n }\n\n private visitLogicBinary(node: AstNode): Value | null {\n const v1 = this.visitChild(node, 0);\n if (v1 === null) {\n return null;\n }\n const b1 = v1 === VALUE_TRUE;\n const attempt = this.tryEvaluateFromFirstArg(node.typeID, b1);\n if (attempt !== null) {\n return attempt;\n }\n\n const v2 = this.visitChild(node, 1);\n if (v2 === null) {\n return null;\n }\n const b2 = v2 === VALUE_TRUE;\n let result: boolean;\n switch (node.typeID) {\n case TokenID.LOGIC_AND:\n result = b1 && b2;\n break;\n case TokenID.LOGIC_OR:\n result = b1 || b2;\n break;\n case TokenID.LOGIC_IMPLICATION:\n result = !b1 || b2;\n break;\n case TokenID.LOGIC_EQUIVALENT:\n result = b1 === b2;\n break;\n default:\n return null;\n }\n return result ? VALUE_TRUE : VALUE_FALSE;\n }\n\n private visitEquals(node: AstNode): Value | null {\n const v1 = this.visitChild(node, 0);\n if (v1 === null) {\n return null;\n }\n const v2 = this.visitChild(node, 1);\n if (v2 === null) {\n return null;\n }\n const areEqual = compare(v1, v2) === 0;\n return areEqual === (node.typeID !== TokenID.NOTEQUAL) ? VALUE_TRUE : VALUE_FALSE;\n }\n\n private visitIntegerPredicate(node: AstNode): Value | null {\n const v1 = this.visitChild(node, 0);\n if (v1 === null) {\n return null;\n }\n const v2 = this.visitChild(node, 1);\n if (v2 === null) {\n return null;\n }\n const a = v1 as number;\n const b = v2 as number;\n let result: boolean;\n switch (node.typeID) {\n case TokenID.GREATER:\n result = a > b;\n break;\n case TokenID.LESSER:\n result = a < b;\n break;\n case TokenID.GREATER_OR_EQ:\n result = a >= b;\n break;\n case TokenID.LESSER_OR_EQ:\n result = a <= b;\n break;\n default:\n return null;\n }\n return result ? VALUE_TRUE : VALUE_FALSE;\n }\n\n private visitSetexprPredicate(node: AstNode): Value | null {\n const v1 = this.visitChild(node, 0);\n if (v1 === null) {\n return null;\n }\n const v2 = this.visitChild(node, 1);\n if (v2 === null) {\n return null;\n }\n let result: boolean;\n switch (node.typeID) {\n case TokenID.SET_IN:\n result = contains(v2 as Value[], v1);\n break;\n case TokenID.SET_NOT_IN:\n result = !contains(v2 as Value[], v1);\n break;\n case TokenID.SUBSET:\n result = compare(v1, v2) !== 0 && isSubsetOrEq(v1 as Value[], v2 as Value[]);\n break;\n case TokenID.NOT_SUBSET:\n result = compare(v1, v2) === 0 || !isSubsetOrEq(v1 as Value[], v2 as Value[]);\n break;\n case TokenID.SUBSET_OR_EQ:\n result = isSubsetOrEq(v1 as Value[], v2 as Value[]);\n break;\n default:\n return null;\n }\n return result ? VALUE_TRUE : VALUE_FALSE;\n }\n\n private visitDecart(node: AstNode): Value | null {\n const args: Value[] = [];\n for (let i = 0; i < node.children.length; i++) {\n const component = this.visitChild(node, i) as Value[];\n if (component === null) {\n return null;\n }\n if (component.length === 0) {\n return EmptySetV;\n }\n args.push(component);\n }\n const result = cartesianProduct(args as Value[][]);\n if (result === null) {\n this.onError(RSErrorCode.setOverflow, node, [String(SET_INFINITY)]);\n return null;\n }\n return result;\n }\n\n private visitBoolean(node: AstNode): Value | null {\n const base = this.visitChild(node, 0) as Value[];\n if (base === null) {\n return null;\n }\n const result = boolean(base);\n if (result === null) {\n this.onError(RSErrorCode.booleanBaseLimit, node.children[0], [String(BOOL_INFINITY)]);\n return null;\n }\n return result;\n }\n\n private visitTuple(node: AstNode): Value | null {\n const args: Value[] = [];\n for (let i = 0; i < node.children.length; i++) {\n const component = this.visitChild(node, i);\n if (component === null) {\n return null;\n }\n args.push(component);\n }\n return tuple(args);\n }\n\n private visitEnumeration(node: AstNode): Value | null {\n const args: Value[] = [];\n for (let i = 0; i < node.children.length; i++) {\n const element = this.visitChild(node, i);\n if (element === null) {\n return null;\n }\n args.push(element);\n }\n return set(args);\n }\n\n private visitBool(node: AstNode): Value | null {\n const element = this.visitChild(node, 0);\n if (element === null) {\n return null;\n }\n return [element];\n }\n\n private visitDebool(node: AstNode): Value | null {\n const target = this.visitChild(node, 0) as Value[];\n if (target === null) {\n return null;\n }\n if (target.length !== 1) {\n return this.onError(RSErrorCode.calcInvalidDebool, node.children[0]);\n }\n return target[0];\n }\n\n private visitSetexprBinary(node: AstNode): Value | null {\n const v1 = this.visitChild(node, 0);\n if (v1 === null) {\n return null;\n }\n const v2 = this.visitChild(node, 1);\n if (v2 === null) {\n return null;\n }\n switch (node.typeID) {\n case TokenID.SET_UNION:\n return setUnion(v1 as Value[], v2 as Value[]);\n case TokenID.SET_INTERSECTION:\n return setIntersection(v1 as Value[], v2 as Value[]);\n case TokenID.SET_MINUS:\n return setDiff(v1 as Value[], v2 as Value[]);\n case TokenID.SET_SYMMETRIC_MINUS:\n return setSymDiff(v1 as Value[], v2 as Value[]);\n }\n return null;\n }\n\n private visitProjectSet(node: AstNode): Value | null {\n const target = this.visitChild(node, 0);\n if (target === null) {\n return null;\n }\n const indices = getNodeIndices(node);\n return projection(target as Value[][], indices);\n }\n\n private visitProjectTuple(node: AstNode): Value | null {\n const target = this.visitChild(node, 0) as Value[];\n if (target === null) {\n return null;\n }\n const indices = getNodeIndices(node);\n const components = indices.map(i => target[i]);\n return components.length === 1 ? components[0] : tuple(components);\n }\n\n private visitFilter(node: AstNode): Value | null {\n const lastIdx = node.children.length - 1;\n const argVal = this.visitChild(node, lastIdx) as Value[][];\n if (argVal === null) {\n return null;\n }\n if (argVal.length === 0) {\n return EmptySetV;\n }\n\n const indices = getNodeIndices(node);\n const tupleParam = indices.length === lastIdx;\n if (tupleParam) {\n const params: Value[] = [];\n for (let i = 0; i < lastIdx; i++) {\n const param = this.visitChild(node, i) as Value[];\n if (param === null) {\n return null;\n }\n if (param.length === 0) {\n return EmptySetV;\n }\n params.push(param);\n }\n const result: Value[] = [];\n for (const element of argVal) {\n let valid = true;\n for (let j = 0; j < indices.length; j++) {\n const comp = element[indices[j]];\n const paramSet = params[j] as Value[];\n if (!contains(paramSet, comp)) {\n valid = false;\n break;\n }\n }\n if (valid) {\n result.push(element);\n }\n }\n return result;\n } else {\n const paramVal = this.visitChild(node, 0) as Value[];\n if (paramVal === null) {\n return null;\n }\n if (paramVal.length === 0) {\n return EmptySetV;\n }\n\n const result: Value[] = [];\n for (const element of argVal) {\n const comps = indices.map(i => element[i]);\n const testElement = comps.length === 1 ? comps[0] : tuple(comps);\n if (contains(paramVal, testElement)) result.push(element);\n }\n return result;\n }\n }\n\n private visitReduce(node: AstNode): Value | null {\n const target = this.visitChild(node, 0);\n if (target === null) {\n return null;\n }\n return reduce(target as Value[][]);\n }\n\n private visitDeclarative(node: AstNode): Value | null {\n const domain = this.visitChild(node, 1);\n if (domain === null) {\n return null;\n }\n\n const elements = [];\n for (const element of domain as Value[]) {\n if (!this.tick(node, TICK_PER_DECLARATIVE)) {\n return null;\n }\n this.dispatchDeclare(node.children[0], element);\n const value = this.visitChild(node, 2);\n if (value === null) {\n return null;\n }\n if (value === VALUE_TRUE) {\n elements.push(element);\n }\n }\n return elements.length === 0 ? EmptySetV : elements;\n }\n\n private visitImperative(node: AstNode): Value | null {\n const result: Value[] = [];\n const frames: IterationFrame[] = [];\n\n let currentChild = 1;\n\n // Advance to next iteration\n const advanceIterator = (): boolean => {\n while (frames.length > 0) {\n const top = frames[frames.length - 1];\n if (top.valueID < top.domain.length - 1) {\n top.valueID++;\n const nextValue = top.domain[top.valueID];\n if (!this.tick(node.children[top.childID], TICK_PER_IMPERATIVE)) {\n return false;\n }\n this.dispatchDeclare(node.children[top.childID].children[0], nextValue);\n currentChild = top.childID + 1;\n return true;\n }\n frames.pop();\n }\n return false;\n };\n\n while (true) {\n // Iteration end - create element and pop up stack\n if (currentChild >= node.children.length) {\n const element = this.visitChild(node, 0);\n if (element === null) {\n return null;\n }\n result.push(element);\n if (!advanceIterator()) {\n break;\n }\n continue;\n }\n\n // Iteration node\n const child = node.children[currentChild];\n if (child.typeID === TokenID.ITERATE) {\n const domain = this.visitChild(child, 1) as Value[];\n if (domain === null) {\n return null;\n }\n if (domain.length === 0) {\n if (!advanceIterator()) {\n break;\n }\n continue;\n }\n if (!this.tick(child, TICK_PER_IMPERATIVE)) {\n return null;\n }\n frames.push({\n childID: currentChild,\n domain,\n valueID: 0\n });\n this.dispatchDeclare(child.children[0], domain[0]);\n currentChild++;\n continue;\n }\n\n // Guard expression\n const value = this.dispatchVisit(child);\n if (value === null) {\n return null;\n }\n if (value === VALUE_FALSE) {\n if (!advanceIterator()) {\n break;\n }\n continue;\n }\n currentChild++;\n }\n return set(result);\n }\n\n private visitAssign(node: AstNode): Value | null {\n const value = this.visitChild(node, 1);\n if (value === null) {\n return null;\n }\n this.dispatchDeclare(node.children[0], value);\n return VALUE_TRUE;\n }\n\n private visitRecursion(node: AstNode): Value | null {\n const initialValue = this.visitChild(node, 1);\n if (initialValue === null) {\n return null;\n }\n const bodyIndex = node.typeID === TokenID.NT_RECURSIVE_FULL ? 3 : 2;\n let current: Value = initialValue;\n while (true) {\n if (!this.tick(node, TICK_PER_RECURSION)) {\n return null;\n }\n\n this.dispatchDeclare(node.children[0], current);\n if (node.typeID === TokenID.NT_RECURSIVE_FULL) {\n const pred = this.visitChild(node, 2);\n if (pred === null) {\n return null;\n }\n if (pred !== VALUE_TRUE) {\n break;\n }\n }\n\n const next = this.visitChild(node, bodyIndex);\n if (next === null) {\n return null;\n }\n if (compare(current, next) === 0) {\n break;\n }\n current = next;\n }\n\n return current;\n }\n}\n\n/** Imperative iteration block data. */\ninterface IterationFrame {\n childID: number;\n domain: Value[];\n valueID: number;\n}\n\n/** Local variable binding with version for cache invalidation. */\ninterface LocalBinding {\n id: number;\n version: number;\n value: Value;\n}\n\n/** Local variables context. */\nclass LocalContext {\n private nextBindingId = 1;\n private data = new Map<string, LocalBinding>();\n private callStack: Map<string, LocalBinding>[] = [];\n\n startScope(): void {\n this.callStack.push(this.data);\n this.data = new Map();\n }\n\n endScope(): void {\n this.data = this.callStack.pop()!;\n }\n\n setLocal(alias: string, value: Value): void {\n const existing = this.data.get(alias);\n if (existing) {\n existing.value = value;\n existing.version++;\n } else {\n this.data.set(alias, { id: this.nextBindingId++, version: 0, value });\n }\n }\n\n findLocal(alias: string): Value | null {\n return this.data.get(alias)?.value ?? null;\n }\n\n buildDependencyStamp(reads: ReadonlySet<string>): string | null {\n if (reads.size === 0) {\n return '';\n }\n const parts: string[] = [];\n for (const alias of [...reads].sort()) {\n const binding = this.data.get(alias);\n if (binding === undefined) {\n return null;\n }\n parts.push(`${binding.id}:${binding.version}`);\n }\n return parts.join('|');\n }\n}\n"],"mappings":"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"}
|
package/dist/rslang/index.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { A 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-hWUoWCba.js";
|
|
2
|
-
import {
|
|
3
|
-
import { i as readTypeAnnotation, r as readErrorAnnotation } from "../ast-annotations-
|
|
2
|
+
import { a as RSErrorDescription, i as RSErrorCode, n as EvalStackFrame, s as formatEvalCallStack } from "../error-S1JghCNN.js";
|
|
3
|
+
import { i as readTypeAnnotation, r as readErrorAnnotation } from "../ast-annotations-DclU1Ser.js";
|
|
4
4
|
import { d as ValuePath, l as Value, p as makeValuePath } from "../value-XpJOVzMP.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-B-1p712X.js";
|
|
6
6
|
import { d as printValue } from "../value-api-Dw8UkwCD.js";
|
|
7
7
|
import { t as parser } from "../parser-DkejtiOR.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-B35QsI3L.js";
|
|
11
11
|
import { n as ArgumentsType } from "../arguments-extractor-CXWRT5Ou.js";
|
|
12
12
|
import { n as applyAsciiTypeSubstitutions, r as parseTypeText } from "../typification-parser-DFxj4JiQ.js";
|
|
13
13
|
import { n as TypificationNodeData, t as TypificationGraph } from "../typification-graph-CSxDt18X.js";
|
|
14
|
-
import "../index-
|
|
15
|
-
export { type AnalysisBase, type AnalysisFast, type AnalysisFull, AnyTypificationT, type ArgumentsType, type CalculatorEvaluateOptions, type CalculatorResult, EmptySetT, type ExpressionType, LogicT, RSCalculator, RSErrorCode, type RSErrorDescription, RSLangAnalyzer, TokenID, TypeClass, TypeID, type TypePath, type Typification, TypificationGraph, type TypificationNodeData, type Value, ValueClass, type ValuePath, applyAsciiTypeSubstitutions, makeTypePath, makeValuePath, parseTypeText, printValue, readErrorAnnotation, readTypeAnnotation, parser as rslangParser };
|
|
14
|
+
import "../index-D-w-bgei.js";
|
|
15
|
+
export { type AnalysisBase, type AnalysisFast, type AnalysisFull, AnyTypificationT, type ArgumentsType, type CalculatorEvaluateOptions, type CalculatorResult, EmptySetT, type EvalStackFrame, type ExpressionType, LogicT, RSCalculator, RSErrorCode, type RSErrorDescription, RSLangAnalyzer, TokenID, TypeClass, TypeID, type TypePath, type Typification, TypificationGraph, type TypificationNodeData, type Value, ValueClass, type ValuePath, applyAsciiTypeSubstitutions, formatEvalCallStack, makeTypePath, makeValuePath, parseTypeText, printValue, readErrorAnnotation, readTypeAnnotation, parser as rslangParser };
|
package/dist/rslang/index.js
CHANGED
|
@@ -2,11 +2,11 @@ import { TokenID } from "./parser/token.js";
|
|
|
2
2
|
import { AnyTypificationT, EmptySetT, LogicT, TypeClass, TypeID, makeTypePath } from "./semantic/typification.js";
|
|
3
3
|
import { parser } from "./parser/parser.js";
|
|
4
4
|
import { readErrorAnnotation, readTypeAnnotation } from "./ast-annotations.js";
|
|
5
|
-
import { RSErrorCode } from "./error.js";
|
|
5
|
+
import { RSErrorCode, formatEvalCallStack } from "./error.js";
|
|
6
6
|
import { C as printValue, u as makeValuePath } from "../value-COprb2Je.js";
|
|
7
7
|
import { RSCalculator } from "./eval/calculator.js";
|
|
8
8
|
import { ValueClass } from "./semantic/value-class.js";
|
|
9
9
|
import { RSLangAnalyzer } from "./semantic/analyzer.js";
|
|
10
10
|
import { applyAsciiTypeSubstitutions, parseTypeText } from "./semantic/typification-parser.js";
|
|
11
11
|
import { TypificationGraph } from "./typification-graph.js";
|
|
12
|
-
export { AnyTypificationT, EmptySetT, LogicT, RSCalculator, RSErrorCode, RSLangAnalyzer, TokenID, TypeClass, TypeID, TypificationGraph, ValueClass, applyAsciiTypeSubstitutions, makeTypePath, makeValuePath, parseTypeText, printValue, readErrorAnnotation, readTypeAnnotation, parser as rslangParser };
|
|
12
|
+
export { AnyTypificationT, EmptySetT, LogicT, RSCalculator, RSErrorCode, RSLangAnalyzer, TokenID, TypeClass, TypeID, TypificationGraph, ValueClass, applyAsciiTypeSubstitutions, formatEvalCallStack, makeTypePath, makeValuePath, parseTypeText, printValue, readErrorAnnotation, readTypeAnnotation, parser as rslangParser };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as AstNode } from "../../../ast-D-D6Rq3T.js";
|
|
2
2
|
import "../../../index-D5RahF1K.js";
|
|
3
3
|
import { g as TypeClass } from "../../../typification-hWUoWCba.js";
|
|
4
|
-
import { t as ErrorReporter } from "../../../error-
|
|
4
|
+
import { t as ErrorReporter } from "../../../error-S1JghCNN.js";
|
|
5
5
|
//#region src/rslang/parser/syntax-errors/index.d.ts
|
|
6
6
|
/** When set, refines incomplete formal headers (`[α∈…]`, quantifiers). */
|
|
7
7
|
interface SyntaxErrorOptions {
|
|
@@ -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-B35QsI3L.js";
|
|
2
2
|
export { AnalysisBase, AnalysisFast, AnalysisFull, AnalysisOptions, RSLangAnalyzer };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as AstNode } from "../../ast-D-D6Rq3T.js";
|
|
2
2
|
import "../../index-D5RahF1K.js";
|
|
3
3
|
import { _ as TypeContext, f as ExpressionType } from "../../typification-hWUoWCba.js";
|
|
4
|
-
import { t as ErrorReporter } from "../../error-
|
|
4
|
+
import { t as ErrorReporter } from "../../error-S1JghCNN.js";
|
|
5
5
|
//#region src/rslang/semantic/type-auditor.d.ts
|
|
6
6
|
/** Type auditor for AST type checking. */
|
|
7
7
|
declare class TypeAuditor {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as AstNode } from "../../ast-D-D6Rq3T.js";
|
|
2
2
|
import "../../index-D5RahF1K.js";
|
|
3
|
-
import { t as ErrorReporter } from "../../error-
|
|
3
|
+
import { t as ErrorReporter } from "../../error-S1JghCNN.js";
|
|
4
4
|
import { n as ValueClassContext, t as ValueClass } from "../../value-class-CNI-lqXJ.js";
|
|
5
5
|
//#region src/rslang/semantic/value-auditor.d.ts
|
|
6
6
|
/** Value auditor for AST value class checking. */
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -81,7 +81,7 @@ export {
|
|
|
81
81
|
} from './parsing/ast';
|
|
82
82
|
export { type CMSyntaxNode, printTree } from './parsing/lezer-tree';
|
|
83
83
|
export { readErrorAnnotation, readTypeAnnotation } from './rslang/ast-annotations';
|
|
84
|
-
export { RSErrorCode, type RSErrorDescription } from './rslang/error';
|
|
84
|
+
export { type EvalStackFrame, formatEvalCallStack,RSErrorCode, type RSErrorDescription } from './rslang/error';
|
|
85
85
|
export { type CalculatorEvaluateOptions, type CalculatorResult, RSCalculator } from './rslang/eval/calculator';
|
|
86
86
|
export { makeValuePath, TUPLE_ID, type Value, type ValuePath } from './rslang/eval/value';
|
|
87
87
|
export { printValue } from './rslang/eval/value-api';
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { type Value } from '../rslang';
|
|
4
|
+
import { compare, TUPLE_ID } from '../rslang/eval/value';
|
|
5
|
+
import { isTupleValue } from '../rslang/eval/value-api';
|
|
6
|
+
import { basic, bool, IntegerT, tuple } from '../rslang/semantic/typification';
|
|
7
|
+
|
|
8
|
+
import { type BasicBinding } from './rsmodel';
|
|
9
|
+
import { generateRandomValue } from './rsmodel-api';
|
|
10
|
+
|
|
11
|
+
function hasUniqueElements(value: Value[]): boolean {
|
|
12
|
+
const sorted = [...value].sort(compare);
|
|
13
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
14
|
+
if (compare(sorted[i - 1], sorted[i]) === 0) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe('generateRandomValue', () => {
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
vi.restoreAllMocks();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('returns unique elements for collections even when samples collide', () => {
|
|
27
|
+
const basics = new Map<number, BasicBinding>([[10, { 1: 'x1', 2: 'x2' }]]);
|
|
28
|
+
const cstByAlias = new Map([['X1', { id: 10 }]]);
|
|
29
|
+
const collectionType = bool(basic('X1'));
|
|
30
|
+
|
|
31
|
+
// Force: size=5, then always pick the same base element id=1.
|
|
32
|
+
const random = vi.spyOn(Math, 'random');
|
|
33
|
+
random
|
|
34
|
+
.mockReturnValueOnce(0.99) // -> 5 elements
|
|
35
|
+
.mockReturnValue(0); // -> always ids[0] === 1
|
|
36
|
+
|
|
37
|
+
const value = generateRandomValue(collectionType, basics, cstByAlias, 5);
|
|
38
|
+
expect(Array.isArray(value)).toBe(true);
|
|
39
|
+
expect(value).toEqual([1]);
|
|
40
|
+
expect(hasUniqueElements(value as Value[])).toBe(true);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('returns unique nested sets for tuple of collections ℬ(X1)×ℬ(C1)', () => {
|
|
44
|
+
const basics = new Map<number, BasicBinding>([
|
|
45
|
+
[10, { 1: 'x1', 2: 'x2' }],
|
|
46
|
+
[20, { 0: 'c0', 1: 'c1', 2: 'c2' }]
|
|
47
|
+
]);
|
|
48
|
+
const cstByAlias = new Map([
|
|
49
|
+
['X1', { id: 10 }],
|
|
50
|
+
['C1', { id: 20 }]
|
|
51
|
+
]);
|
|
52
|
+
const type = tuple([bool(basic('X1')), bool(basic('C1'))]);
|
|
53
|
+
|
|
54
|
+
for (let attempt = 0; attempt < 30; attempt++) {
|
|
55
|
+
const value = generateRandomValue(type, basics, cstByAlias, 10);
|
|
56
|
+
expect(isTupleValue(value)).toBe(true);
|
|
57
|
+
const tupleValue = value as Value[];
|
|
58
|
+
expect(tupleValue[0]).toBe(TUPLE_ID);
|
|
59
|
+
expect(Array.isArray(tupleValue[1])).toBe(true);
|
|
60
|
+
expect(Array.isArray(tupleValue[2])).toBe(true);
|
|
61
|
+
expect(hasUniqueElements(tupleValue[1] as Value[])).toBe(true);
|
|
62
|
+
expect(hasUniqueElements(tupleValue[2] as Value[])).toBe(true);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('returns null when a basic domain is empty', () => {
|
|
67
|
+
const basics = new Map<number, BasicBinding>();
|
|
68
|
+
const cstByAlias = new Map([['X1', { id: 10 }]]);
|
|
69
|
+
expect(generateRandomValue(basic('X1'), basics, cstByAlias)).toBeNull();
|
|
70
|
+
expect(generateRandomValue(bool(basic('X1')), basics, cstByAlias)).toBeNull();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('generates integers in range', () => {
|
|
74
|
+
const value = generateRandomValue(IntegerT, new Map(), new Map());
|
|
75
|
+
expect(typeof value).toBe('number');
|
|
76
|
+
expect(value as number).toBeGreaterThanOrEqual(-100);
|
|
77
|
+
expect(value as number).toBeLessThanOrEqual(100);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ExpressionType, TypeID, type Typification, type Value } from '../rslang';
|
|
2
|
-
import { compare, tuple, TUPLE_ID, VALUE_TRUE, type ValuePath } from '../rslang/eval/value';
|
|
2
|
+
import { compare, set, tuple, TUPLE_ID, VALUE_TRUE, type ValuePath } from '../rslang/eval/value';
|
|
3
3
|
import { extractValue, isTupleValue, makeDefaultValue, setNestedValue } from '../rslang/eval/value-api';
|
|
4
4
|
import { type EchelonCollection } from '../rslang/semantic/typification';
|
|
5
5
|
|
|
@@ -71,6 +71,11 @@ export function generateRandomValue(
|
|
|
71
71
|
return tuple(factors);
|
|
72
72
|
}
|
|
73
73
|
case TypeID.collection: {
|
|
74
|
+
// Empty set is a valid sample only when the element domain itself is generatable.
|
|
75
|
+
// When the count happens to be 0 we would otherwise skip sampling and miss empty basics.
|
|
76
|
+
if (!canGenerateRandomValue(type.base, basics, cstByAlias)) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
74
79
|
const result: Value[] = [];
|
|
75
80
|
const randomElementsCount = Math.floor(Math.random() * (setElementsCount + 1));
|
|
76
81
|
for (let i = 0; i < randomElementsCount; i++) {
|
|
@@ -80,7 +85,8 @@ export function generateRandomValue(
|
|
|
80
85
|
}
|
|
81
86
|
result.push(sample);
|
|
82
87
|
}
|
|
83
|
-
|
|
88
|
+
// Sets must be unique; sampling with replacement can produce duplicates.
|
|
89
|
+
return set(result);
|
|
84
90
|
}
|
|
85
91
|
case TypeID.anyTypification:
|
|
86
92
|
return null;
|
|
@@ -330,6 +336,28 @@ export function addValueElement(
|
|
|
330
336
|
|
|
331
337
|
// ========= Internal functions ==========
|
|
332
338
|
|
|
339
|
+
function canGenerateRandomValue(
|
|
340
|
+
type: Typification,
|
|
341
|
+
basics: Map<number, BasicBinding>,
|
|
342
|
+
cstByAlias: Map<string, { id: number }>
|
|
343
|
+
): boolean {
|
|
344
|
+
switch (type.typeID) {
|
|
345
|
+
case TypeID.integer:
|
|
346
|
+
return true;
|
|
347
|
+
case TypeID.basic: {
|
|
348
|
+
const cst = cstByAlias.get(type.baseID);
|
|
349
|
+
const binding = cst ? basics.get(cst.id) : undefined;
|
|
350
|
+
return Object.keys(binding ?? {}).length > 0;
|
|
351
|
+
}
|
|
352
|
+
case TypeID.tuple:
|
|
353
|
+
return type.factors.every(factor => canGenerateRandomValue(factor, basics, cstByAlias));
|
|
354
|
+
case TypeID.collection:
|
|
355
|
+
return canGenerateRandomValue(type.base, basics, cstByAlias);
|
|
356
|
+
case TypeID.anyTypification:
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
333
361
|
function countBaseElements(cst: ModelEvalFields, engine: RSEngine): number {
|
|
334
362
|
if (!isBasicConcept(cst.cst_type)) {
|
|
335
363
|
return 0;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { type EvalStackFrame,formatEvalCallStack } from './error';
|
|
4
|
+
|
|
5
|
+
describe('formatEvalCallStack', () => {
|
|
6
|
+
it('returns empty string for missing or empty stack', () => {
|
|
7
|
+
expect(formatEvalCallStack(undefined)).toBe('');
|
|
8
|
+
expect(formatEvalCallStack([])).toBe('');
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('formats callee aliases from outermost call to innermost fault', () => {
|
|
12
|
+
const stack: EvalStackFrame[] = [
|
|
13
|
+
{ alias: 'F12', from: 10, to: 12 },
|
|
14
|
+
{ alias: 'F5', from: 8, to: 14 }
|
|
15
|
+
];
|
|
16
|
+
expect(formatEvalCallStack(stack)).toBe('F5 → F12');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('formats a single nested call', () => {
|
|
20
|
+
const stack: EvalStackFrame[] = [{ alias: 'F9', from: 7, to: 8 }];
|
|
21
|
+
expect(formatEvalCallStack(stack)).toBe('F9');
|
|
22
|
+
});
|
|
23
|
+
});
|
package/src/rslang/error.ts
CHANGED
|
@@ -16,15 +16,57 @@ export interface RSErrorInfo {
|
|
|
16
16
|
params?: readonly string[];
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* One frame of an evaluation call chain.
|
|
21
|
+
*
|
|
22
|
+
* Spans are relative to the formal definition of {@link alias}.
|
|
23
|
+
* Frames are ordered innermost-first: fault locus, then each caller outward.
|
|
24
|
+
* The root expression under evaluation is not a frame — its highlight is
|
|
25
|
+
* {@link RSErrorDescription.from}/{@link RSErrorDescription.to}; {@link RSErrorDescription.stack}
|
|
26
|
+
* is absent when the fault is in that root expression.
|
|
27
|
+
*/
|
|
28
|
+
export interface EvalStackFrame {
|
|
29
|
+
/** Constituent whose formal definition contains this span. */
|
|
30
|
+
alias: string;
|
|
31
|
+
/** Half-open span `[from, to)` in that definition. */
|
|
32
|
+
from: number;
|
|
33
|
+
to: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
19
36
|
/** Represents RSLang expression error description. */
|
|
20
37
|
export interface RSErrorDescription extends RSErrorInfo {
|
|
21
38
|
from: number;
|
|
22
39
|
to: number;
|
|
40
|
+
/**
|
|
41
|
+
* Evaluation call chain when the fault is inside a called `F#`/`P#` body.
|
|
42
|
+
* Absent for parse/semantic errors and for evaluation errors in the root expression.
|
|
43
|
+
*/
|
|
44
|
+
stack?: readonly EvalStackFrame[];
|
|
23
45
|
}
|
|
24
46
|
|
|
25
47
|
/** Error reporter function type. */
|
|
26
48
|
export type ErrorReporter = (error: RSErrorDescription) => void;
|
|
27
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Formats an evaluation call chain for display (`F5 → F12`).
|
|
52
|
+
*
|
|
53
|
+
* Uses callee aliases from outermost call to innermost fault container.
|
|
54
|
+
* Returns an empty string when there is no nested call to show.
|
|
55
|
+
*/
|
|
56
|
+
export function formatEvalCallStack(stack: readonly EvalStackFrame[] | undefined): string {
|
|
57
|
+
if (!stack || stack.length === 0) {
|
|
58
|
+
return '';
|
|
59
|
+
}
|
|
60
|
+
const aliases: string[] = [];
|
|
61
|
+
for (let index = stack.length - 1; index >= 0; index--) {
|
|
62
|
+
const frame = stack[index];
|
|
63
|
+
if (frame) {
|
|
64
|
+
aliases.push(frame.alias);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return aliases.join(' → ');
|
|
68
|
+
}
|
|
69
|
+
|
|
28
70
|
/** Represents RSLang expression error types. */
|
|
29
71
|
export const RSErrorCode = {
|
|
30
72
|
unknownSyntax: 0x8400, // 33792
|
|
@@ -308,11 +308,66 @@ describe('Calculator', () => {
|
|
|
308
308
|
expect(errors[0]).toMatchObject({
|
|
309
309
|
code: RSErrorCode.iterateInfinity,
|
|
310
310
|
from: callSite!.from,
|
|
311
|
-
to: callSite!.to
|
|
311
|
+
to: callSite!.to,
|
|
312
|
+
stack: [{ alias: 'F9', from: zOffset, to: zOffset + 1 }]
|
|
312
313
|
});
|
|
314
|
+
expect(errors[0]?.stack).toHaveLength(1);
|
|
313
315
|
expect(readErrorAnnotation(callSite!)).toMatchObject({ code: RSErrorCode.iterateInfinity });
|
|
314
316
|
expect(readErrorAnnotation(innerErrorNode!)).toBeNull();
|
|
315
317
|
});
|
|
318
|
+
|
|
319
|
+
it('keeps nested call surface span in the root expression and records the full stack', () => {
|
|
320
|
+
const innerExpr = '[a∈X1] debool(∅)';
|
|
321
|
+
const midExpr = '[a∈X1] F8[a]';
|
|
322
|
+
treeContext.set('F8', buildAST(innerExpr));
|
|
323
|
+
treeContext.set('F7', buildAST(midExpr));
|
|
324
|
+
const mainAst = buildAST('F7[X1]');
|
|
325
|
+
const outerCall = findFirstNode(mainAst, TokenID.NT_FUNC_CALL);
|
|
326
|
+
expect(outerCall).not.toBeNull();
|
|
327
|
+
|
|
328
|
+
const midAst = treeContext.get('F7')!;
|
|
329
|
+
const midCall = findFirstNode(midAst, TokenID.NT_FUNC_CALL);
|
|
330
|
+
expect(midCall).not.toBeNull();
|
|
331
|
+
|
|
332
|
+
const deboolArgFrom = innerExpr.indexOf('∅');
|
|
333
|
+
calculator.run(mainAst, error => errors.push(error), true);
|
|
334
|
+
|
|
335
|
+
expect(errors).toHaveLength(1);
|
|
336
|
+
expect(errors[0]).toMatchObject({
|
|
337
|
+
code: RSErrorCode.calcInvalidDebool,
|
|
338
|
+
from: outerCall!.from,
|
|
339
|
+
to: outerCall!.to,
|
|
340
|
+
stack: [
|
|
341
|
+
{ alias: 'F8', from: deboolArgFrom, to: deboolArgFrom + 1 },
|
|
342
|
+
{ alias: 'F7', from: midCall!.from, to: midCall!.to }
|
|
343
|
+
]
|
|
344
|
+
});
|
|
345
|
+
expect(errors[0]?.stack).toHaveLength(2);
|
|
346
|
+
expect(readErrorAnnotation(outerCall!)).toMatchObject({ code: RSErrorCode.calcInvalidDebool });
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
it('distinguishes which call site failed when the same function is used twice', () => {
|
|
350
|
+
treeContext.set('F8', buildAST('[a∈ℬ(X1)] debool(a)'));
|
|
351
|
+
const mainAst = buildAST('F8[{1}] ∪ F8[X1]');
|
|
352
|
+
const callSites: AstNode[] = [];
|
|
353
|
+
visitAstDFS(mainAst, node => {
|
|
354
|
+
if (node.typeID === TokenID.NT_FUNC_CALL) {
|
|
355
|
+
callSites.push(node);
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
expect(callSites).toHaveLength(2);
|
|
359
|
+
|
|
360
|
+
calculator.run(mainAst, error => errors.push(error));
|
|
361
|
+
|
|
362
|
+
expect(errors).toHaveLength(1);
|
|
363
|
+
expect(errors[0]).toMatchObject({
|
|
364
|
+
code: RSErrorCode.calcInvalidDebool,
|
|
365
|
+
from: callSites[1].from,
|
|
366
|
+
to: callSites[1].to,
|
|
367
|
+
stack: [{ alias: 'F8' }]
|
|
368
|
+
});
|
|
369
|
+
expect(errors[0]?.stack).toHaveLength(1);
|
|
370
|
+
});
|
|
316
371
|
});
|
|
317
372
|
|
|
318
373
|
describe('evaluation cache', () => {
|