affinirum 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +301 -0
- package/dst/Affinirum.d.ts +73 -0
- package/dst/Affinirum.js +536 -0
- package/dst/Constant.d.ts +15 -0
- package/dst/Constant.js +26 -0
- package/dst/Constants.d.ts +2 -0
- package/dst/Constants.js +22 -0
- package/dst/Functions.d.ts +2 -0
- package/dst/Functions.js +85 -0
- package/dst/Keywords.d.ts +1 -0
- package/dst/Keywords.js +17 -0
- package/dst/Node.d.ts +13 -0
- package/dst/Node.js +22 -0
- package/dst/ParserFrame.d.ts +13 -0
- package/dst/ParserFrame.js +80 -0
- package/dst/ParserState.d.ts +54 -0
- package/dst/ParserState.js +562 -0
- package/dst/StaticScope.d.ts +13 -0
- package/dst/StaticScope.js +44 -0
- package/dst/Type.d.ts +72 -0
- package/dst/Type.js +196 -0
- package/dst/Value.d.ts +3 -0
- package/dst/Value.js +1 -0
- package/dst/Variable.d.ts +13 -0
- package/dst/Variable.js +25 -0
- package/dst/atom/ArrayAtom.d.ts +11 -0
- package/dst/atom/ArrayAtom.js +38 -0
- package/dst/atom/FunctionAtom.d.ts +17 -0
- package/dst/atom/FunctionAtom.js +54 -0
- package/dst/atom/ObjectAtom.d.ts +11 -0
- package/dst/atom/ObjectAtom.js +44 -0
- package/dst/atom/PrimitiveAtom.d.ts +8 -0
- package/dst/atom/PrimitiveAtom.js +26 -0
- package/dst/cjs/Affinirum.js +540 -0
- package/dst/cjs/Constant.js +30 -0
- package/dst/cjs/Constants.js +25 -0
- package/dst/cjs/Functions.js +88 -0
- package/dst/cjs/Keywords.js +20 -0
- package/dst/cjs/Node.js +26 -0
- package/dst/cjs/ParserFrame.js +84 -0
- package/dst/cjs/ParserState.js +566 -0
- package/dst/cjs/StaticScope.js +48 -0
- package/dst/cjs/Type.js +200 -0
- package/dst/cjs/Value.js +2 -0
- package/dst/cjs/Variable.js +29 -0
- package/dst/cjs/atom/ArrayAtom.js +42 -0
- package/dst/cjs/atom/FunctionAtom.js +58 -0
- package/dst/cjs/atom/ObjectAtom.js +48 -0
- package/dst/cjs/atom/PrimitiveAtom.js +30 -0
- package/dst/cjs/constant/Array.js +93 -0
- package/dst/cjs/constant/Boolean.js +25 -0
- package/dst/cjs/constant/Buffer.js +68 -0
- package/dst/cjs/constant/Enumerable.js +34 -0
- package/dst/cjs/constant/Float.js +85 -0
- package/dst/cjs/constant/Integer.js +104 -0
- package/dst/cjs/constant/Iterable.js +24 -0
- package/dst/cjs/constant/Number.js +59 -0
- package/dst/cjs/constant/Object.js +13 -0
- package/dst/cjs/constant/String.js +197 -0
- package/dst/cjs/constant/Timestamp.js +56 -0
- package/dst/cjs/constant/Unknown.js +101 -0
- package/dst/cjs/constant/notation/AN.js +46 -0
- package/dst/cjs/constant/notation/JSON.js +14 -0
- package/dst/cjs/index.js +19 -0
- package/dst/cjs/node/ArrayNode.js +34 -0
- package/dst/cjs/node/BlockNode.js +33 -0
- package/dst/cjs/node/CallNode.js +54 -0
- package/dst/cjs/node/ConstantNode.js +33 -0
- package/dst/cjs/node/LoopNode.js +34 -0
- package/dst/cjs/node/ObjectNode.js +42 -0
- package/dst/cjs/node/SwitchNode.js +45 -0
- package/dst/cjs/node/VariableNode.js +30 -0
- package/dst/cjs/package.json +3 -0
- package/dst/constant/Array.d.ts +22 -0
- package/dst/constant/Array.js +90 -0
- package/dst/constant/Boolean.d.ts +11 -0
- package/dst/constant/Boolean.js +22 -0
- package/dst/constant/Buffer.d.ts +10 -0
- package/dst/constant/Buffer.js +61 -0
- package/dst/constant/Enumerable.d.ts +5 -0
- package/dst/constant/Enumerable.js +31 -0
- package/dst/constant/Float.d.ts +22 -0
- package/dst/constant/Float.js +80 -0
- package/dst/constant/Integer.d.ts +10 -0
- package/dst/constant/Integer.js +100 -0
- package/dst/constant/Iterable.d.ts +3 -0
- package/dst/constant/Iterable.js +21 -0
- package/dst/constant/Number.d.ts +14 -0
- package/dst/constant/Number.js +56 -0
- package/dst/constant/Object.d.ts +7 -0
- package/dst/constant/Object.js +10 -0
- package/dst/constant/String.d.ts +34 -0
- package/dst/constant/String.js +179 -0
- package/dst/constant/Timestamp.d.ts +20 -0
- package/dst/constant/Timestamp.js +50 -0
- package/dst/constant/Unknown.d.ts +10 -0
- package/dst/constant/Unknown.js +95 -0
- package/dst/constant/notation/AN.d.ts +6 -0
- package/dst/constant/notation/AN.js +42 -0
- package/dst/constant/notation/JSON.d.ts +7 -0
- package/dst/constant/notation/JSON.js +10 -0
- package/dst/index.d.ts +3 -0
- package/dst/index.js +3 -0
- package/dst/node/ArrayNode.d.ts +12 -0
- package/dst/node/ArrayNode.js +30 -0
- package/dst/node/BlockNode.d.ts +12 -0
- package/dst/node/BlockNode.js +29 -0
- package/dst/node/CallNode.d.ts +14 -0
- package/dst/node/CallNode.js +50 -0
- package/dst/node/ConstantNode.d.ts +15 -0
- package/dst/node/ConstantNode.js +29 -0
- package/dst/node/LoopNode.d.ts +13 -0
- package/dst/node/LoopNode.js +30 -0
- package/dst/node/ObjectNode.d.ts +13 -0
- package/dst/node/ObjectNode.js +38 -0
- package/dst/node/SwitchNode.d.ts +14 -0
- package/dst/node/SwitchNode.js +41 -0
- package/dst/node/VariableNode.d.ts +14 -0
- package/dst/node/VariableNode.js +26 -0
- package/package.json +67 -0
|
@@ -0,0 +1,540 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Affinirum = void 0;
|
|
4
|
+
const Boolean_js_1 = require("./constant/Boolean.js");
|
|
5
|
+
const Enumerable_js_1 = require("./constant/Enumerable.js");
|
|
6
|
+
const Iterable_js_1 = require("./constant/Iterable.js");
|
|
7
|
+
const Number_js_1 = require("./constant/Number.js");
|
|
8
|
+
const Unknown_js_1 = require("./constant/Unknown.js");
|
|
9
|
+
const Constant_js_1 = require("./Constant.js");
|
|
10
|
+
const Variable_js_1 = require("./Variable.js");
|
|
11
|
+
const Type_js_1 = require("./Type.js");
|
|
12
|
+
const Keywords_js_1 = require("./Keywords.js");
|
|
13
|
+
const Constants_js_1 = require("./Constants.js");
|
|
14
|
+
const Functions_js_1 = require("./Functions.js");
|
|
15
|
+
const ArrayNode_js_1 = require("./node/ArrayNode.js");
|
|
16
|
+
const BlockNode_js_1 = require("./node/BlockNode.js");
|
|
17
|
+
const ConstantNode_js_1 = require("./node/ConstantNode.js");
|
|
18
|
+
const CallNode_js_1 = require("./node/CallNode.js");
|
|
19
|
+
const LoopNode_js_1 = require("./node/LoopNode.js");
|
|
20
|
+
const ObjectNode_js_1 = require("./node/ObjectNode.js");
|
|
21
|
+
const SwitchNode_js_1 = require("./node/SwitchNode.js");
|
|
22
|
+
const VariableNode_js_1 = require("./node/VariableNode.js");
|
|
23
|
+
const ParserState_js_1 = require("./ParserState.js");
|
|
24
|
+
const StaticScope_js_1 = require("./StaticScope.js");
|
|
25
|
+
class Affinirum {
|
|
26
|
+
static keywords = [...Keywords_js_1.Keywords, ...Constants_js_1.Constants.map((c) => c[0])];
|
|
27
|
+
_script;
|
|
28
|
+
_strict;
|
|
29
|
+
_root;
|
|
30
|
+
_vframes = new Map();
|
|
31
|
+
_variables = new Map();
|
|
32
|
+
_constants = new Map(Constants_js_1.Constants);
|
|
33
|
+
_functions = new Map(Functions_js_1.Functions);
|
|
34
|
+
_scope = new StaticScope_js_1.StaticScope();
|
|
35
|
+
/**
|
|
36
|
+
Creates compiled expression. Any parsed token not recognized as a constant or a function will be compiled as a variable.
|
|
37
|
+
@param script Math expression to compile.
|
|
38
|
+
@param config Optional expected type, strict mode, variable types, constant values and functions to add for the compilation.
|
|
39
|
+
If expected type is provided then expression return type is matched against it.
|
|
40
|
+
If strict mode is set then undeclared variables will not be allowed in expression.
|
|
41
|
+
*/
|
|
42
|
+
constructor(script, config) {
|
|
43
|
+
this._script = script;
|
|
44
|
+
this._strict = config?.strict ?? false;
|
|
45
|
+
if (config?.variables) {
|
|
46
|
+
for (const v in config.variables) {
|
|
47
|
+
this._variables.set(v, new Variable_js_1.Variable(config.variables[v]));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const state = new ParserState_js_1.ParserState(this._script);
|
|
51
|
+
this._root = this._block(state.next(), this._scope);
|
|
52
|
+
if (!state.isVoid) {
|
|
53
|
+
state.throwError('unexpected expression token or expression end');
|
|
54
|
+
}
|
|
55
|
+
this._root = this._root.compile(config?.type ?? Type_js_1.Type.Unknown);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
Returns original script text.
|
|
59
|
+
*/
|
|
60
|
+
get script() {
|
|
61
|
+
return this._script;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
Returns compiled expression return value type.
|
|
65
|
+
*/
|
|
66
|
+
get type() {
|
|
67
|
+
return this._root.type;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
Returns string representing parsed node tree structure.
|
|
71
|
+
@returns Parsed expression string.
|
|
72
|
+
*/
|
|
73
|
+
toString() {
|
|
74
|
+
return this._root.toString();
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
Returns record with compiled variable names and expected types.
|
|
78
|
+
@returns Record with variable names and types.
|
|
79
|
+
*/
|
|
80
|
+
variables() {
|
|
81
|
+
const types = {};
|
|
82
|
+
const variables = this._scope.variables();
|
|
83
|
+
for (const name in variables) {
|
|
84
|
+
types[name] = variables[name].type;
|
|
85
|
+
}
|
|
86
|
+
return types;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
Evaluates compiled expression using provided variable values.
|
|
90
|
+
@param values Record with variable names and values.
|
|
91
|
+
@returns Calculated value.
|
|
92
|
+
*/
|
|
93
|
+
evaluate(values) {
|
|
94
|
+
const variables = this._scope.variables();
|
|
95
|
+
for (const name in variables) {
|
|
96
|
+
if (!Object.prototype.hasOwnProperty.call(values, name)) {
|
|
97
|
+
this._vframes.get(name)?.throwError(`undefined variable ${name}:\n`);
|
|
98
|
+
}
|
|
99
|
+
const variable = variables[name];
|
|
100
|
+
const value = values?.[name] ?? undefined;
|
|
101
|
+
if (!variable.type.match(Type_js_1.Type.of(value))) {
|
|
102
|
+
this._vframes.get(name)?.throwError(`unexpected type ${Type_js_1.Type.of(value)} for variable ${name} of type ${variable.type}:\n`);
|
|
103
|
+
}
|
|
104
|
+
variable.value = value;
|
|
105
|
+
}
|
|
106
|
+
return this._root.evaluate();
|
|
107
|
+
}
|
|
108
|
+
_block(state, scope) {
|
|
109
|
+
const frame = state.starts();
|
|
110
|
+
const nodes = [this._unit(state, scope)];
|
|
111
|
+
while (state.isSemicolonSeparator) {
|
|
112
|
+
nodes.push(this._unit(state.next(), scope));
|
|
113
|
+
}
|
|
114
|
+
return new BlockNode_js_1.BlockNode(frame.ends(state), nodes);
|
|
115
|
+
}
|
|
116
|
+
_unit(state, scope) {
|
|
117
|
+
return this._disjunction(state, scope);
|
|
118
|
+
}
|
|
119
|
+
_disjunction(state, scope) {
|
|
120
|
+
let node = this._conjunction(state, scope);
|
|
121
|
+
while (state.operator === Boolean_js_1.funcOr) {
|
|
122
|
+
node = this._call(state.starts(), state.operator, [node, this._conjunction(state.next(), scope)]);
|
|
123
|
+
}
|
|
124
|
+
return node;
|
|
125
|
+
}
|
|
126
|
+
_conjunction(state, scope) {
|
|
127
|
+
let node = this._comparison(state, scope);
|
|
128
|
+
while (state.operator === Boolean_js_1.funcAnd) {
|
|
129
|
+
node = this._call(state.starts(), state.operator, [node, this._comparison(state.next(), scope)]);
|
|
130
|
+
}
|
|
131
|
+
return node;
|
|
132
|
+
}
|
|
133
|
+
_comparison(state, scope) {
|
|
134
|
+
const frame = state.starts();
|
|
135
|
+
let not = false;
|
|
136
|
+
while (state.operator === Boolean_js_1.funcNot) {
|
|
137
|
+
not = !not;
|
|
138
|
+
frame.starts(state);
|
|
139
|
+
state.next();
|
|
140
|
+
}
|
|
141
|
+
let node = this._aggregate(state, scope);
|
|
142
|
+
while (state.operator === Number_js_1.funcGreaterThan || state.operator === Number_js_1.funcLessThan
|
|
143
|
+
|| state.operator === Number_js_1.funcGreaterOrEqual || state.operator === Number_js_1.funcLessOrEqual
|
|
144
|
+
|| state.operator === Unknown_js_1.funcEqual || state.operator === Unknown_js_1.funcNotEqual) {
|
|
145
|
+
node = this._call(state.starts(), state.operator, [node, this._aggregate(state.next(), scope)]);
|
|
146
|
+
}
|
|
147
|
+
if (not) {
|
|
148
|
+
node = this._call(frame.ends(state), Boolean_js_1.funcNot, [node]);
|
|
149
|
+
}
|
|
150
|
+
return node;
|
|
151
|
+
}
|
|
152
|
+
_aggregate(state, scope) {
|
|
153
|
+
let node = this._product(state, scope);
|
|
154
|
+
while (state.operator === Enumerable_js_1.funcAdd || state.operator === Number_js_1.funcSubtract) {
|
|
155
|
+
node = this._call(state.starts(), state.operator, [node, this._product(state.next(), scope)]);
|
|
156
|
+
}
|
|
157
|
+
return node;
|
|
158
|
+
}
|
|
159
|
+
_product(state, scope) {
|
|
160
|
+
let node = this._factor(state, scope);
|
|
161
|
+
while (state.operator === Number_js_1.funcMultiply || state.operator === Number_js_1.funcDivide || state.operator === Number_js_1.funcRemainder) {
|
|
162
|
+
node = this._call(state.starts(), state.operator, [node, this._factor(state.next(), scope)]);
|
|
163
|
+
}
|
|
164
|
+
return node;
|
|
165
|
+
}
|
|
166
|
+
_factor(state, scope) {
|
|
167
|
+
const frame = state.starts();
|
|
168
|
+
let neg = false;
|
|
169
|
+
while (state.operator === Number_js_1.funcSubtract) {
|
|
170
|
+
neg = !neg;
|
|
171
|
+
frame.starts(state);
|
|
172
|
+
state.next();
|
|
173
|
+
}
|
|
174
|
+
let node = this._coalescence(state, scope);
|
|
175
|
+
while (state.operator === Number_js_1.funcPower) {
|
|
176
|
+
node = this._call(state.starts(), state.operator, [node, this._coalescence(state.next(), scope)]);
|
|
177
|
+
}
|
|
178
|
+
if (neg) {
|
|
179
|
+
node = this._call(frame.ends(state), Number_js_1.funcNegate, [node]);
|
|
180
|
+
}
|
|
181
|
+
return node;
|
|
182
|
+
}
|
|
183
|
+
_coalescence(state, scope) {
|
|
184
|
+
let node = this._accessor(state, scope);
|
|
185
|
+
while (state.operator === Unknown_js_1.funcCoalesce) {
|
|
186
|
+
node = this._call(state.starts(), state.operator, [node, this._accessor(state.next(), scope)]);
|
|
187
|
+
}
|
|
188
|
+
return node;
|
|
189
|
+
}
|
|
190
|
+
_accessor(state, scope) {
|
|
191
|
+
let node = this._term(state, scope);
|
|
192
|
+
while (state.operator === Iterable_js_1.funcAt || state.isParenthesesOpen || state.isBracketsOpen) {
|
|
193
|
+
const frame = state.starts();
|
|
194
|
+
if (state.operator === Iterable_js_1.funcAt) {
|
|
195
|
+
if (state.next().isLiteral && (typeof state.literalValue === 'string' || typeof state.literalValue === 'bigint')) {
|
|
196
|
+
node = this._call(frame.ends(state), Iterable_js_1.funcAt, [node, new ConstantNode_js_1.ConstantNode(state, new Constant_js_1.Constant(state.literalValue))]);
|
|
197
|
+
state.next();
|
|
198
|
+
}
|
|
199
|
+
else if (state.isToken) {
|
|
200
|
+
frame.ends(state);
|
|
201
|
+
const func = this._functions.get(state.token);
|
|
202
|
+
if (func) {
|
|
203
|
+
if (state.next().isParenthesesOpen) {
|
|
204
|
+
const subnodes = [node];
|
|
205
|
+
while (!state.next().isParenthesesClose) {
|
|
206
|
+
subnodes.push(this._unit(state, scope));
|
|
207
|
+
if (!state.isCommaSeparator) {
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
node = this._call(frame.ends(state), func, subnodes);
|
|
212
|
+
state.closeParentheses().next();
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
node = this._call(frame, func, [node]);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
node = this._call(frame, Iterable_js_1.funcAt, [node, new ConstantNode_js_1.ConstantNode(state, new Constant_js_1.Constant(state.token))]);
|
|
220
|
+
state.next();
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
state.throwError('missing array or object index');
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
else if (state.isParenthesesOpen) {
|
|
228
|
+
const subnodes = [];
|
|
229
|
+
while (!state.next().isParenthesesClose) {
|
|
230
|
+
subnodes.push(this._unit(state, scope));
|
|
231
|
+
if (!state.isCommaSeparator) {
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
node = new CallNode_js_1.CallNode(frame.ends(state), node, subnodes);
|
|
236
|
+
state.closeParentheses().next();
|
|
237
|
+
}
|
|
238
|
+
else if (state.isBracketsOpen) {
|
|
239
|
+
node = this._call(frame, Iterable_js_1.funcAt, [node, this._unit(state.next(), scope)]);
|
|
240
|
+
state.closeBrackets().next();
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return node;
|
|
244
|
+
}
|
|
245
|
+
_term(state, scope) {
|
|
246
|
+
if (state.isLiteral) {
|
|
247
|
+
const frame = state.starts();
|
|
248
|
+
const constant = new Constant_js_1.Constant(state.literalValue);
|
|
249
|
+
state.next();
|
|
250
|
+
return new ConstantNode_js_1.ConstantNode(frame, constant);
|
|
251
|
+
}
|
|
252
|
+
else if (state.isToken) {
|
|
253
|
+
const frame = state.starts();
|
|
254
|
+
const constants = this._constants.get(state.token);
|
|
255
|
+
if (constants != null) {
|
|
256
|
+
if (state.next().operator !== Iterable_js_1.funcAt) {
|
|
257
|
+
state.throwError('missing constant accessor operator');
|
|
258
|
+
}
|
|
259
|
+
if (!state.next().isToken) {
|
|
260
|
+
state.throwError('missing constant name');
|
|
261
|
+
}
|
|
262
|
+
const constant = constants[state.token];
|
|
263
|
+
if (!constant) {
|
|
264
|
+
state.throwError(`unknown constant ${state.token}`);
|
|
265
|
+
}
|
|
266
|
+
state.next();
|
|
267
|
+
return new ConstantNode_js_1.ConstantNode(frame, constant);
|
|
268
|
+
}
|
|
269
|
+
let variable = scope.get(state.token);
|
|
270
|
+
if (variable == null) {
|
|
271
|
+
variable = this._variables.get(state.token);
|
|
272
|
+
if (variable == null) {
|
|
273
|
+
if (this._strict) {
|
|
274
|
+
state.throwError(`undefined variable ${state.token} in strict mode`);
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
variable = new Variable_js_1.Variable();
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
scope.global(state.token, variable);
|
|
281
|
+
}
|
|
282
|
+
if (!this._vframes.has(state.token)) {
|
|
283
|
+
this._vframes.set(state.token, state.starts());
|
|
284
|
+
}
|
|
285
|
+
if (state.next().isAssignment) {
|
|
286
|
+
if (variable.constant) {
|
|
287
|
+
state.throwError('illegal constant assignment');
|
|
288
|
+
}
|
|
289
|
+
if (state.assignmentOperator) {
|
|
290
|
+
const operator = state.assignmentOperator;
|
|
291
|
+
const subnodes = [new VariableNode_js_1.VariableNode(frame, variable), this._unit(state.next(), scope)];
|
|
292
|
+
return new VariableNode_js_1.VariableNode(frame, variable, this._call(frame, operator, subnodes));
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
return new VariableNode_js_1.VariableNode(frame, variable, this._unit(state.next(), scope));
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return new VariableNode_js_1.VariableNode(frame, variable);
|
|
299
|
+
}
|
|
300
|
+
else if (state.isBracesOpen) {
|
|
301
|
+
const node = this._block(state.next(), scope);
|
|
302
|
+
state.closeBraces().next();
|
|
303
|
+
return node;
|
|
304
|
+
}
|
|
305
|
+
else if (state.isBracesClose) {
|
|
306
|
+
state.throwError('unexpected closing braces');
|
|
307
|
+
}
|
|
308
|
+
else if (state.isParenthesesOpen) {
|
|
309
|
+
const node = this._unit(state.next(), scope);
|
|
310
|
+
state.closeParentheses().next();
|
|
311
|
+
return node;
|
|
312
|
+
}
|
|
313
|
+
else if (state.isParenthesesClose) {
|
|
314
|
+
state.throwError('unexpected closing parentheses');
|
|
315
|
+
}
|
|
316
|
+
else if (state.isBracketsOpen) {
|
|
317
|
+
const frame = state.starts();
|
|
318
|
+
const subnodes = [];
|
|
319
|
+
let index = 0, colon = false;
|
|
320
|
+
while (!state.next().isBracketsClose) {
|
|
321
|
+
if (state.isColonSeparator) {
|
|
322
|
+
colon = true;
|
|
323
|
+
state.next();
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
const node = this._unit(state, scope);
|
|
327
|
+
if (state.isColonSeparator) {
|
|
328
|
+
colon = true;
|
|
329
|
+
subnodes.push([node, this._unit(state.next(), scope)]);
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
subnodes.push([index++, node]);
|
|
333
|
+
}
|
|
334
|
+
if (!state.isCommaSeparator) {
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
frame.ends(state);
|
|
339
|
+
state.closeBrackets().next();
|
|
340
|
+
if (colon) {
|
|
341
|
+
return new ObjectNode_js_1.ObjectNode(frame, subnodes.map(([k, v]) => [typeof k === 'number' ? new ConstantNode_js_1.ConstantNode(v, new Constant_js_1.Constant(String(k))) : k, v]));
|
|
342
|
+
}
|
|
343
|
+
return new ArrayNode_js_1.ArrayNode(frame, subnodes.map(([, v]) => v));
|
|
344
|
+
}
|
|
345
|
+
else if (state.isBracketsClose) {
|
|
346
|
+
state.throwError('unexpected closing brackets');
|
|
347
|
+
}
|
|
348
|
+
else if (state.isVariableDefinition || state.isConstantDefinition) {
|
|
349
|
+
const constant = state.isConstantDefinition;
|
|
350
|
+
if (!state.next().isToken) {
|
|
351
|
+
state.throwError(`missing ${constant ? 'constant' : 'variable'} name`);
|
|
352
|
+
}
|
|
353
|
+
const token = state.token;
|
|
354
|
+
if (scope.has(token)) {
|
|
355
|
+
state.throwError(`illegal redefinition of ${constant ? 'constant' : 'variable'} ${token}`);
|
|
356
|
+
}
|
|
357
|
+
const frame = state.starts();
|
|
358
|
+
let type;
|
|
359
|
+
if (state.next().isColonSeparator) {
|
|
360
|
+
type = this._type(state.next(), scope);
|
|
361
|
+
}
|
|
362
|
+
const variable = new Variable_js_1.Variable(type, constant);
|
|
363
|
+
scope.local(token, variable);
|
|
364
|
+
if (state.isAssignment) {
|
|
365
|
+
if (state.assignmentOperator) {
|
|
366
|
+
state.throwError(`illegal assignment to ${constant ? 'constant' : 'variable'} ${token}`);
|
|
367
|
+
}
|
|
368
|
+
return new VariableNode_js_1.VariableNode(frame, variable, this._unit(state.next(), scope));
|
|
369
|
+
}
|
|
370
|
+
return new VariableNode_js_1.VariableNode(frame, variable);
|
|
371
|
+
}
|
|
372
|
+
else if (state.isTildaMark) {
|
|
373
|
+
return this._function(state, scope);
|
|
374
|
+
}
|
|
375
|
+
else if (state.isWhile) {
|
|
376
|
+
return this._loop(state, scope);
|
|
377
|
+
}
|
|
378
|
+
else if (state.isIf) {
|
|
379
|
+
return this._switch(state, scope);
|
|
380
|
+
}
|
|
381
|
+
else if (state.isVoid) {
|
|
382
|
+
state.throwError('unexpected end of expression');
|
|
383
|
+
}
|
|
384
|
+
state.throwError('unexpected expression token');
|
|
385
|
+
}
|
|
386
|
+
_function(state, scope) {
|
|
387
|
+
const frame = state.starts();
|
|
388
|
+
let retType = undefined;
|
|
389
|
+
if (!state.next().isParenthesesOpen) {
|
|
390
|
+
retType = this._type(state, scope);
|
|
391
|
+
state.openParentheses();
|
|
392
|
+
}
|
|
393
|
+
let variadic = false;
|
|
394
|
+
const variables = new Map();
|
|
395
|
+
while (!state.next().isParenthesesClose) {
|
|
396
|
+
if (!state.isToken) {
|
|
397
|
+
state.throwError('missing function argument name');
|
|
398
|
+
}
|
|
399
|
+
const token = state.token;
|
|
400
|
+
if (scope.get(token)) {
|
|
401
|
+
state.throwError('variable redefinition');
|
|
402
|
+
}
|
|
403
|
+
let argType = Type_js_1.Type.Unknown;
|
|
404
|
+
if (state.next().isColonSeparator) {
|
|
405
|
+
argType = this._type(state.next(), scope);
|
|
406
|
+
}
|
|
407
|
+
variables.set(token, new Variable_js_1.Variable(argType));
|
|
408
|
+
if (argType.isArray && state.isVariadicFunction) {
|
|
409
|
+
variadic = true;
|
|
410
|
+
state.next();
|
|
411
|
+
break;
|
|
412
|
+
}
|
|
413
|
+
if (!state.isCommaSeparator) {
|
|
414
|
+
break;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
state.closeParentheses();
|
|
418
|
+
frame.ends(state);
|
|
419
|
+
state.next().openBraces().next();
|
|
420
|
+
const subnode = this._block(state, scope.subscope(variables));
|
|
421
|
+
state.closeBraces().next();
|
|
422
|
+
const args = Array.from(variables.values());
|
|
423
|
+
const value = (...values) => {
|
|
424
|
+
args.forEach((arg, ix) => arg.value = values[ix]);
|
|
425
|
+
return subnode.evaluate();
|
|
426
|
+
};
|
|
427
|
+
if (!retType && args.length) {
|
|
428
|
+
retType = Type_js_1.Type.Unknown;
|
|
429
|
+
}
|
|
430
|
+
const constant = new Constant_js_1.Constant(value, Type_js_1.Type.functionType(retType, args.map((v) => v.type), variadic));
|
|
431
|
+
return new ConstantNode_js_1.ConstantNode(frame, constant, subnode);
|
|
432
|
+
}
|
|
433
|
+
_loop(state, scope) {
|
|
434
|
+
const frame = state.starts();
|
|
435
|
+
const cnode = this._unit(state.next(), scope);
|
|
436
|
+
frame.ends(state);
|
|
437
|
+
state.openBraces().next();
|
|
438
|
+
const subnode = this._block(state, scope);
|
|
439
|
+
state.closeBraces().next();
|
|
440
|
+
return new LoopNode_js_1.LoopNode(frame, cnode, subnode);
|
|
441
|
+
}
|
|
442
|
+
_switch(state, scope) {
|
|
443
|
+
const frame = state.starts();
|
|
444
|
+
const cnode = this._unit(state.next(), scope);
|
|
445
|
+
frame.ends(state);
|
|
446
|
+
const subnodes = [];
|
|
447
|
+
state.openBraces().next();
|
|
448
|
+
subnodes.push(this._block(state, scope));
|
|
449
|
+
state.closeBraces().next();
|
|
450
|
+
if (state.isElse) {
|
|
451
|
+
state.next().openBraces().next();
|
|
452
|
+
subnodes.push(this._block(state, scope));
|
|
453
|
+
state.closeBraces().next();
|
|
454
|
+
}
|
|
455
|
+
else {
|
|
456
|
+
subnodes.push(new ConstantNode_js_1.ConstantNode(state.starts(), Constant_js_1.Constant.Null));
|
|
457
|
+
}
|
|
458
|
+
return new SwitchNode_js_1.SwitchNode(frame, cnode, subnodes);
|
|
459
|
+
}
|
|
460
|
+
_call(frame, func, subnodes) {
|
|
461
|
+
return new CallNode_js_1.CallNode(frame, new ConstantNode_js_1.ConstantNode(frame, func), subnodes);
|
|
462
|
+
}
|
|
463
|
+
_type(state, scope) {
|
|
464
|
+
if (state.isType) {
|
|
465
|
+
let type = state.type;
|
|
466
|
+
if (state.next().isOptionalType) {
|
|
467
|
+
type = type.toOptional();
|
|
468
|
+
state.next();
|
|
469
|
+
}
|
|
470
|
+
if (state.operator === Boolean_js_1.funcOr) { // type union
|
|
471
|
+
return Type_js_1.Type.union(type, this._type(state.next(), scope));
|
|
472
|
+
}
|
|
473
|
+
return type;
|
|
474
|
+
}
|
|
475
|
+
else if (state.isBracketsOpen) { // array or object type
|
|
476
|
+
const itemPropTypes = [];
|
|
477
|
+
let index = 0, colon = false;
|
|
478
|
+
while (!state.next().isBracketsClose) {
|
|
479
|
+
if (state.isColonSeparator) { // default object type
|
|
480
|
+
colon = true;
|
|
481
|
+
state.next();
|
|
482
|
+
break;
|
|
483
|
+
}
|
|
484
|
+
if (state.isType) {
|
|
485
|
+
itemPropTypes.push([index++, this._type(state, scope)]);
|
|
486
|
+
}
|
|
487
|
+
else if (state.isToken) {
|
|
488
|
+
const token = state.token;
|
|
489
|
+
state.next().separateByColon().next();
|
|
490
|
+
itemPropTypes.push([token, this._type(state, scope)]);
|
|
491
|
+
}
|
|
492
|
+
else {
|
|
493
|
+
state.throwError('missing type or property name');
|
|
494
|
+
}
|
|
495
|
+
if (!state.isCommaSeparator) {
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
state.closeBrackets().next();
|
|
500
|
+
return colon
|
|
501
|
+
? Type_js_1.Type.objectType(Object.fromEntries(itemPropTypes.map(([prop, type]) => [prop, type])))
|
|
502
|
+
: Type_js_1.Type.arrayType(itemPropTypes.map(([, v]) => v));
|
|
503
|
+
}
|
|
504
|
+
else if (state.isTildaMark) { // function type
|
|
505
|
+
let retType = undefined;
|
|
506
|
+
if (!state.next().isParenthesesOpen) {
|
|
507
|
+
retType = this._type(state, scope);
|
|
508
|
+
state.openParentheses();
|
|
509
|
+
}
|
|
510
|
+
let variadic = false;
|
|
511
|
+
const argTypes = [];
|
|
512
|
+
while (!state.next().isParenthesesClose) {
|
|
513
|
+
const argType = this._type(state, scope);
|
|
514
|
+
argTypes.push(argType);
|
|
515
|
+
if (state.isVariadicFunction) {
|
|
516
|
+
if (argType.isArray) {
|
|
517
|
+
variadic = true;
|
|
518
|
+
state.next();
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
521
|
+
else {
|
|
522
|
+
state.throwError('variadic function argument must be an array type');
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
if (!state.isCommaSeparator) {
|
|
526
|
+
break;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
state.closeParentheses().next();
|
|
530
|
+
if (!retType && argTypes.length) {
|
|
531
|
+
retType = Type_js_1.Type.Unknown;
|
|
532
|
+
}
|
|
533
|
+
return Type_js_1.Type.functionType(retType, argTypes, variadic);
|
|
534
|
+
}
|
|
535
|
+
else {
|
|
536
|
+
state.throwError('missing type name');
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
exports.Affinirum = Affinirum;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Constant = void 0;
|
|
4
|
+
const Type_js_1 = require("./Type.js");
|
|
5
|
+
class Constant {
|
|
6
|
+
_value;
|
|
7
|
+
_type;
|
|
8
|
+
_deterministic;
|
|
9
|
+
constructor(_value, _type = Type_js_1.Type.of(_value), _deterministic = true) {
|
|
10
|
+
this._value = _value;
|
|
11
|
+
this._type = _type;
|
|
12
|
+
this._deterministic = _deterministic;
|
|
13
|
+
}
|
|
14
|
+
get value() {
|
|
15
|
+
return this._value;
|
|
16
|
+
}
|
|
17
|
+
get type() {
|
|
18
|
+
return Type_js_1.Type.isPrimitiveType(this._value) ? Type_js_1.Type.of(this._value) : this._type;
|
|
19
|
+
}
|
|
20
|
+
set type(type) {
|
|
21
|
+
this._type = type;
|
|
22
|
+
}
|
|
23
|
+
get deterministic() {
|
|
24
|
+
return this._deterministic;
|
|
25
|
+
}
|
|
26
|
+
static Null = new Constant(undefined);
|
|
27
|
+
static EmptyArray = new Constant([]);
|
|
28
|
+
static EmptyObject = new Constant({});
|
|
29
|
+
}
|
|
30
|
+
exports.Constant = Constant;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Constants = void 0;
|
|
4
|
+
const Array_js_1 = require("./constant/Array.js");
|
|
5
|
+
const Boolean_js_1 = require("./constant/Boolean.js");
|
|
6
|
+
const Buffer_js_1 = require("./constant/Buffer.js");
|
|
7
|
+
const Integer_js_1 = require("./constant/Integer.js");
|
|
8
|
+
const Float_js_1 = require("./constant/Float.js");
|
|
9
|
+
const Object_js_1 = require("./constant/Object.js");
|
|
10
|
+
const String_js_1 = require("./constant/String.js");
|
|
11
|
+
const Timestamp_js_1 = require("./constant/Timestamp.js");
|
|
12
|
+
const AN_js_1 = require("./constant/notation/AN.js");
|
|
13
|
+
const JSON_js_1 = require("./constant/notation/JSON.js");
|
|
14
|
+
exports.Constants = [
|
|
15
|
+
['Array', Array_js_1.constArray],
|
|
16
|
+
['Boolean', Boolean_js_1.constBoolean],
|
|
17
|
+
['Buffer', Buffer_js_1.constBuffer],
|
|
18
|
+
['Float', Float_js_1.constFloat],
|
|
19
|
+
['Integer', Integer_js_1.constInteger],
|
|
20
|
+
['Object', Object_js_1.constObject],
|
|
21
|
+
['String', String_js_1.constString],
|
|
22
|
+
['Timestamp', Timestamp_js_1.constTimestamp],
|
|
23
|
+
['AN', AN_js_1.constAN],
|
|
24
|
+
['JSON', JSON_js_1.constJSON],
|
|
25
|
+
];
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Functions = void 0;
|
|
4
|
+
const Array_js_1 = require("./constant/Array.js");
|
|
5
|
+
const Buffer_js_1 = require("./constant/Buffer.js");
|
|
6
|
+
const Enumerable_js_1 = require("./constant/Enumerable.js");
|
|
7
|
+
const Iterable_js_1 = require("./constant/Iterable.js");
|
|
8
|
+
const Number_js_1 = require("./constant/Number.js");
|
|
9
|
+
const Object_js_1 = require("./constant/Object.js");
|
|
10
|
+
const String_js_1 = require("./constant/String.js");
|
|
11
|
+
const Timestamp_js_1 = require("./constant/Timestamp.js");
|
|
12
|
+
const Unknown_js_1 = require("./constant/Unknown.js");
|
|
13
|
+
exports.Functions = [
|
|
14
|
+
// Array
|
|
15
|
+
['First', Array_js_1.funcFirst],
|
|
16
|
+
['Last', Array_js_1.funcLast],
|
|
17
|
+
['FirstIndex', Array_js_1.funcFirstIndex],
|
|
18
|
+
['LastIndex', Array_js_1.funcLastIndex],
|
|
19
|
+
['Any', Array_js_1.funcAny],
|
|
20
|
+
['Every', Array_js_1.funcEvery],
|
|
21
|
+
['Flatten', Array_js_1.funcFlatten],
|
|
22
|
+
['Reverse', Array_js_1.funcReverse],
|
|
23
|
+
['Mutate', Array_js_1.funcMutate],
|
|
24
|
+
['Filter', Array_js_1.funcFilter],
|
|
25
|
+
['Reduce', Array_js_1.funcReduce],
|
|
26
|
+
['Compose', Array_js_1.funcCompose],
|
|
27
|
+
['Prepend', Array_js_1.funcPrepend],
|
|
28
|
+
['Append', Array_js_1.funcAppend],
|
|
29
|
+
// Buffer
|
|
30
|
+
['Byte', Buffer_js_1.funcByte],
|
|
31
|
+
// Enumerable
|
|
32
|
+
['Add', Enumerable_js_1.funcAdd],
|
|
33
|
+
['Slice', Enumerable_js_1.funcSlice],
|
|
34
|
+
['Splice', Enumerable_js_1.funcSplice],
|
|
35
|
+
['Inject', Enumerable_js_1.funcInject],
|
|
36
|
+
// Iterable
|
|
37
|
+
['Length', Iterable_js_1.funcLength],
|
|
38
|
+
['At', Iterable_js_1.funcAt],
|
|
39
|
+
// Number
|
|
40
|
+
['GreaterThan', Number_js_1.funcGreaterThan],
|
|
41
|
+
['LessThan', Number_js_1.funcLessThan],
|
|
42
|
+
['GreaterOrEqual', Number_js_1.funcGreaterOrEqual],
|
|
43
|
+
['LessOrEqual', Number_js_1.funcLessOrEqual],
|
|
44
|
+
['Subtract', Number_js_1.funcSubtract],
|
|
45
|
+
['Multiply', Number_js_1.funcMultiply],
|
|
46
|
+
['Divide', Number_js_1.funcDivide],
|
|
47
|
+
['Remainder', Number_js_1.funcRemainder],
|
|
48
|
+
['Modulo', Number_js_1.funcModulo],
|
|
49
|
+
['Power', Number_js_1.funcPower],
|
|
50
|
+
['Root', Number_js_1.funcRoot],
|
|
51
|
+
['Negate', Number_js_1.funcNegate],
|
|
52
|
+
['Cast', Number_js_1.funcCast],
|
|
53
|
+
// Object
|
|
54
|
+
['Entries', Object_js_1.funcEntries],
|
|
55
|
+
['Keys', Object_js_1.funcKeys],
|
|
56
|
+
['Values', Object_js_1.funcValues],
|
|
57
|
+
// String
|
|
58
|
+
['Like', String_js_1.funcLike],
|
|
59
|
+
['Unlike', String_js_1.funcUnlike],
|
|
60
|
+
['Contains', String_js_1.funcContains],
|
|
61
|
+
['StartsWith', String_js_1.funcStartsWith],
|
|
62
|
+
['EndsWith', String_js_1.funcEndsWith],
|
|
63
|
+
['Char', String_js_1.funcChar],
|
|
64
|
+
['CharCode', String_js_1.funcCharCode],
|
|
65
|
+
['Trim', String_js_1.funcTrim],
|
|
66
|
+
['TrimStart', String_js_1.funcTrimStart],
|
|
67
|
+
['TrimEnd', String_js_1.funcTrimEnd],
|
|
68
|
+
['LowerCase', String_js_1.funcLowerCase],
|
|
69
|
+
['UpperCase', String_js_1.funcUpperCase],
|
|
70
|
+
['Split', String_js_1.funcSplit],
|
|
71
|
+
// Timestamp
|
|
72
|
+
['Year', Timestamp_js_1.funcYear],
|
|
73
|
+
['Month', Timestamp_js_1.funcMonth],
|
|
74
|
+
['MonthIndex', Timestamp_js_1.funcMonthIndex],
|
|
75
|
+
['WeekdayIndex', Timestamp_js_1.funcWeekdayIndex],
|
|
76
|
+
['Day', Timestamp_js_1.funcDay],
|
|
77
|
+
['Hour', Timestamp_js_1.funcHour],
|
|
78
|
+
['Minute', Timestamp_js_1.funcMinute],
|
|
79
|
+
['Second', Timestamp_js_1.funcSecond],
|
|
80
|
+
['Millisecond', Timestamp_js_1.funcMillisecond],
|
|
81
|
+
['EpochTime', Timestamp_js_1.funcEpochTime],
|
|
82
|
+
// Unknown
|
|
83
|
+
['Coalesce', Unknown_js_1.funcCoalesce],
|
|
84
|
+
['Equal', Unknown_js_1.funcEqual],
|
|
85
|
+
['Unequal', Unknown_js_1.funcNotEqual],
|
|
86
|
+
['Encode', Unknown_js_1.funcEncode],
|
|
87
|
+
['Format', Unknown_js_1.funcFormat],
|
|
88
|
+
];
|