affinirum 1.1.4 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +8 -8
  2. package/dst/Affinirum.d.ts +2 -0
  3. package/dst/Affinirum.js +74 -70
  4. package/dst/Constant.d.ts +0 -3
  5. package/dst/Constant.js +0 -3
  6. package/dst/Keywords.js +9 -9
  7. package/dst/ParserState.d.ts +9 -9
  8. package/dst/ParserState.js +77 -88
  9. package/dst/Type.d.ts +2 -3
  10. package/dst/Type.js +13 -29
  11. package/dst/Variable.d.ts +3 -3
  12. package/dst/Variable.js +5 -5
  13. package/dst/atom/ArrayAtom.d.ts +1 -1
  14. package/dst/atom/ArrayAtom.js +3 -3
  15. package/dst/atom/FunctionAtom.d.ts +4 -4
  16. package/dst/atom/FunctionAtom.js +23 -11
  17. package/dst/atom/ObjectAtom.d.ts +1 -1
  18. package/dst/atom/ObjectAtom.js +3 -4
  19. package/dst/atom/PrimitiveAtom.d.ts +1 -0
  20. package/dst/atom/PrimitiveAtom.js +3 -0
  21. package/dst/cjs/Affinirum.js +74 -70
  22. package/dst/cjs/Constant.js +0 -3
  23. package/dst/cjs/Keywords.js +9 -9
  24. package/dst/cjs/ParserState.js +76 -87
  25. package/dst/cjs/Type.js +13 -29
  26. package/dst/cjs/Variable.js +5 -5
  27. package/dst/cjs/atom/ArrayAtom.js +3 -3
  28. package/dst/cjs/atom/FunctionAtom.js +23 -11
  29. package/dst/cjs/atom/ObjectAtom.js +3 -4
  30. package/dst/cjs/atom/PrimitiveAtom.js +3 -0
  31. package/dst/cjs/constant/Float.js +14 -14
  32. package/dst/cjs/constant/Integer.js +31 -31
  33. package/dst/cjs/constant/String.js +30 -26
  34. package/dst/cjs/constant/Unknown.js +4 -4
  35. package/dst/cjs/constant/notation/AN.js +1 -1
  36. package/dst/cjs/node/CallNode.js +0 -8
  37. package/dst/constant/Float.d.ts +3 -2
  38. package/dst/constant/Float.js +12 -12
  39. package/dst/constant/Integer.d.ts +2 -1
  40. package/dst/constant/Integer.js +31 -31
  41. package/dst/constant/String.d.ts +11 -8
  42. package/dst/constant/String.js +20 -18
  43. package/dst/constant/Timestamp.d.ts +3 -2
  44. package/dst/constant/Unknown.d.ts +5 -1
  45. package/dst/constant/Unknown.js +5 -5
  46. package/dst/constant/notation/AN.js +2 -2
  47. package/dst/node/CallNode.js +0 -8
  48. package/package.json +1 -1
package/README.md CHANGED
@@ -27,7 +27,7 @@ The value of a block is determined by the value of the last expression.
27
27
  - Scientific notation is supported for floating point numbers, like *0.1281e+2*.
28
28
  - ISO Timestamps prefixed with **@**, like *@2025-05-11T19:09:21.320Z*.
29
29
  - Hexadecimal buffer values are enclosed in backtick (**\`**) quotes, like *\`10ab0901\`*.
30
- - String literals are enclosed in single (**'**), or double (**"**) quotes, like *'string value'*.
30
+ - String literals are enclosed in single (**'**), or double (**"**) quotes, like *'string value1'*, or *"string value2"*.
31
31
 
32
32
  Array is an ordered sequence of values of any type.
33
33
  It is defined by comma-separated values enclosed in brackets (**[]**),
@@ -41,12 +41,12 @@ Easy way to check if array contains an index is to use presence operator (**?**)
41
41
 
42
42
  Object is a container of named values of any type.
43
43
  It is defined by comma-separated key-value pair enclosed in brackets (**[]**) where key is separated from value by colon (**:**),
44
- like *["NumericProperty":100, "StringProperty":"abc"]*, *["a":0,"b":"str":"c":valueVar]*.
44
+ like *["key1":100, "key2":"abc"]*, *["a":0,"b":"str":"c":valueVar]*.
45
45
  <br>An empty object is represented as **[\:]**.
46
46
 
47
47
  Object properties can be accessed using the access operator (**.**) with a string literal, token,
48
48
  or with brackets containing a string key,
49
- like *theObject."StringProperty"*, *theObject.stringProp*, *theObject["StringProperty"]*.
49
+ like *theObject."key"*, *theObject.key*, or *theObject["key"]*.
50
50
 
51
51
  Easy way to check if object contains a key is to use presence operator (**?**), like *theObject?myKey*.
52
52
 
@@ -64,12 +64,12 @@ Whitespace characters are ignored.
64
64
  - **void** for value **null**
65
65
  - **boolean** for values **true** and **false**
66
66
  - **timestamp** for date-time values, millisecons since Unix epoch
67
- - **float** IEEE 754 double-precision binary floating-point format: binary64
67
+ - **float** for 64-bit floating point values in binary64, IEEE 754 binary floating-point format
68
68
  - **integer** for 64-bit integer values
69
69
  - **buffer** for ordered sequences of bytes
70
70
  - **string** for ordered sequences of characters, text strings
71
- - **array** for ordered sequences of valuese
72
- - **object** for sets of named values
71
+ - **array** for ordered sequences of values
72
+ - **object** for collections of named values
73
73
  - **function** for built-in, injected or script-defined subroutines
74
74
 
75
75
  Type modifier **?** can be used to make any type optional (nullable).
@@ -299,12 +299,12 @@ const objExpr = new Affinirum( '[`prop1`:a,`prop2`:`abc`].prop1+10' );
299
299
  const oValue = objExpr.evaluate( { a: 50 } ); // 60
300
300
  ...
301
301
  const iteratorExpr = new Affinirum(
302
- 'Float.Sum(arr1.Derive(float(a:float)->a*2).Filter(boolean(a:float)->a>3))'
302
+ 'Float.Sum(arr1.Derive(float(a:float){a*2}).Filter(boolean(a:float){a>3}))'
303
303
  );
304
304
  const iValue = iteratorExpr.evaluate( { arr1: [ 1, 2, 3 ] } ); // 10
305
305
  ...
306
306
  const complexExpr = new Affinirum(
307
- 'var a=myvar1/10, const b=myvar2-100, a/b + b*a + 600'
307
+ 'var a=myvar1/10, val b=myvar2-100, a/b + b*a + 600'
308
308
  );
309
309
  const value = complexExpr.evaluate( { myvar1: 40, myvar2: 104 } ); // 4761
310
310
  ...
@@ -59,9 +59,11 @@ export declare class Affinirum {
59
59
  protected _coalescence(state: ParserState, scope: StaticScope): Node;
60
60
  protected _disjunction(state: ParserState, scope: StaticScope): Node;
61
61
  protected _conjunction(state: ParserState, scope: StaticScope): Node;
62
+ protected _negation(state: ParserState, scope: StaticScope): Node;
62
63
  protected _comparison(state: ParserState, scope: StaticScope): Node;
63
64
  protected _aggregate(state: ParserState, scope: StaticScope): Node;
64
65
  protected _product(state: ParserState, scope: StaticScope): Node;
66
+ protected _signum(state: ParserState, scope: StaticScope): Node;
65
67
  protected _factor(state: ParserState, scope: StaticScope): Node;
66
68
  protected _accessor(state: ParserState, scope: StaticScope): Node;
67
69
  protected _term(state: ParserState, scope: StaticScope): Node;
package/dst/Affinirum.js CHANGED
@@ -105,7 +105,7 @@ export class Affinirum {
105
105
  _block(state, scope) {
106
106
  const frame = state.starts();
107
107
  const nodes = [this._unit(state, scope)];
108
- while (state.isSemicolonSeparator) {
108
+ while (state.isSemicolon) {
109
109
  nodes.push(this._unit(state.next(), scope));
110
110
  }
111
111
  return new BlockNode(frame.ends(state), nodes);
@@ -128,29 +128,33 @@ export class Affinirum {
128
128
  return node;
129
129
  }
130
130
  _conjunction(state, scope) {
131
- let node = this._comparison(state, scope);
131
+ let node = this._negation(state, scope);
132
132
  while (state.operator === funcAnd) {
133
- node = this._call(state.starts(), state.operator, [node, this._comparison(state.next(), scope)]);
133
+ node = this._call(state.starts(), state.operator, [node, this._negation(state.next(), scope)]);
134
134
  }
135
135
  return node;
136
136
  }
137
- _comparison(state, scope) {
137
+ _negation(state, scope) {
138
138
  const frame = state.starts();
139
- let not = false;
139
+ let negate = false;
140
140
  while (state.operator === funcNot) {
141
- not = !not;
142
- frame.starts(state);
141
+ negate = !negate;
142
+ frame.ends(state);
143
143
  state.next();
144
144
  }
145
+ let node = this._comparison(state, scope);
146
+ if (negate) {
147
+ node = this._call(frame, funcNot, [node]);
148
+ }
149
+ return node;
150
+ }
151
+ _comparison(state, scope) {
145
152
  let node = this._aggregate(state, scope);
146
153
  while (state.operator === funcGreaterThan || state.operator === funcLessThan
147
154
  || state.operator === funcGreaterOrEqual || state.operator === funcLessOrEqual
148
155
  || state.operator === funcEqual || state.operator === funcNotEqual) {
149
156
  node = this._call(state.starts(), state.operator, [node, this._aggregate(state.next(), scope)]);
150
157
  }
151
- if (not) {
152
- node = this._call(frame.ends(state), funcNot, [node]);
153
- }
154
158
  return node;
155
159
  }
156
160
  _aggregate(state, scope) {
@@ -161,35 +165,41 @@ export class Affinirum {
161
165
  return node;
162
166
  }
163
167
  _product(state, scope) {
164
- let node = this._factor(state, scope);
168
+ let node = this._signum(state, scope);
165
169
  while (state.operator === funcMultiply || state.operator === funcDivide || state.operator === funcRemainder) {
166
- node = this._call(state.starts(), state.operator, [node, this._factor(state.next(), scope)]);
170
+ node = this._call(state.starts(), state.operator, [node, this._signum(state.next(), scope)]);
167
171
  }
168
172
  return node;
169
173
  }
170
- _factor(state, scope) {
174
+ _signum(state, scope) {
171
175
  const frame = state.starts();
172
- let neg = false;
173
- while (state.operator === funcSubtract) {
174
- neg = !neg;
175
- frame.starts(state);
176
+ let negate = false;
177
+ while (state.operator === funcAdd || state.operator === funcSubtract) {
178
+ if (state.operator === funcSubtract) {
179
+ negate = !negate;
180
+ }
181
+ frame.ends(state);
176
182
  state.next();
177
183
  }
184
+ let node = this._factor(state, scope);
185
+ if (negate) {
186
+ node = this._call(frame.ends(state), funcNegate, [node]);
187
+ }
188
+ return node;
189
+ }
190
+ _factor(state, scope) {
178
191
  let node = this._accessor(state, scope);
179
192
  while (state.operator === funcPower) {
180
193
  node = this._call(state.starts(), state.operator, [node, this._accessor(state.next(), scope)]);
181
194
  }
182
- if (neg) {
183
- node = this._call(frame.ends(state), funcNegate, [node]);
184
- }
185
195
  return node;
186
196
  }
187
197
  _accessor(state, scope) {
188
198
  let node = this._term(state, scope);
189
- while (state.isDotMark || state.isQuestionMark || state.isParenthesesOpen || state.isBracketsOpen) {
199
+ while (state.isDot || state.isQuestion || state.isParenthesesOpen || state.isBracketsOpen) {
190
200
  const frame = state.starts();
191
- if (state.isDotMark || state.isQuestionMark) {
192
- const operator = state.isDotMark ? funcAt : funcHas;
201
+ if (state.isDot || state.isQuestion) {
202
+ const operator = state.isDot ? funcAt : funcHas;
193
203
  if (state.next().isLiteral && (typeof state.literal.value === "string" || typeof state.literal.value === "bigint")) {
194
204
  node = this._call(frame.ends(state), operator, [node, new ConstantNode(state, new Constant(state.literal.value))]);
195
205
  state.next();
@@ -202,7 +212,7 @@ export class Affinirum {
202
212
  const subnodes = [node];
203
213
  while (!state.next().isParenthesesClose) {
204
214
  subnodes.push(this._unit(state, scope));
205
- if (!state.isCommaSeparator) {
215
+ if (!state.isComma) {
206
216
  break;
207
217
  }
208
218
  }
@@ -226,7 +236,7 @@ export class Affinirum {
226
236
  const subnodes = [];
227
237
  while (!state.next().isParenthesesClose) {
228
238
  subnodes.push(this._unit(state, scope));
229
- if (!state.isCommaSeparator) {
239
+ if (!state.isComma) {
230
240
  break;
231
241
  }
232
242
  }
@@ -251,7 +261,7 @@ export class Affinirum {
251
261
  const frame = state.starts();
252
262
  const constants = this._constants.get(state.token);
253
263
  if (constants != null) {
254
- if (!state.next().isDotMark) {
264
+ if (!state.next().isDot) {
255
265
  state.throwError("missing constant accessor operator");
256
266
  }
257
267
  if (!state.next().isToken) {
@@ -281,8 +291,8 @@ export class Affinirum {
281
291
  this._vframes.set(state.token, state.starts());
282
292
  }
283
293
  if (state.next().isAssignment) {
284
- if (variable.constant) {
285
- state.throwError("illegal constant assignment");
294
+ if (!variable.assignable) {
295
+ state.throwError("illegal re-assignment");
286
296
  }
287
297
  if (state.assignment.operator) {
288
298
  const operator = state.assignment.operator;
@@ -316,20 +326,20 @@ export class Affinirum {
316
326
  const subnodes = [];
317
327
  let index = 0, colon = false;
318
328
  while (!state.next().isBracketsClose) {
319
- if (state.isColonSeparator) {
329
+ if (state.isColon) {
320
330
  colon = true;
321
331
  state.next();
322
332
  break;
323
333
  }
324
334
  const node = this._unit(state, scope);
325
- if (state.isColonSeparator) {
335
+ if (state.isColon) {
326
336
  colon = true;
327
337
  subnodes.push([node, this._unit(state.next(), scope)]);
328
338
  }
329
339
  else {
330
340
  subnodes.push([index++, node]);
331
341
  }
332
- if (!state.isCommaSeparator) {
342
+ if (!state.isComma) {
333
343
  break;
334
344
  }
335
345
  }
@@ -343,31 +353,31 @@ export class Affinirum {
343
353
  else if (state.isBracketsClose) {
344
354
  state.throwError("unexpected closing brackets");
345
355
  }
346
- else if (state.isVariableDefinition || state.isConstantDefinition) {
347
- const constant = state.isConstantDefinition;
356
+ else if (state.isVariable || state.isValue) {
357
+ const assignable = state.isVariable;
348
358
  if (!state.next().isToken) {
349
- state.throwError(`missing ${constant ? "constant" : "variable"} name`);
359
+ state.throwError(`missing variable name`);
350
360
  }
351
361
  const token = state.token;
352
362
  if (scope.has(token)) {
353
- state.throwError(`illegal redefinition of ${constant ? "constant" : "variable"} ${token}`);
363
+ state.throwError(`illegal redefinition of variable ${token}`);
354
364
  }
355
365
  const frame = state.starts();
356
366
  let type;
357
- if (state.next().isColonSeparator) {
367
+ if (state.next().isColon) {
358
368
  type = this._type(state.next(), scope);
359
369
  }
360
- const variable = new Variable(type, constant);
370
+ const variable = new Variable(type, assignable);
361
371
  scope.local(token, variable);
362
372
  if (state.isAssignment) {
363
373
  if (state.assignment.operator) {
364
- state.throwError(`illegal assignment operator to ${constant ? "constant" : "variable"} ${token}`);
374
+ state.throwError(`illegal assignment operator with variable ${token}`);
365
375
  }
366
376
  return new VariableNode(frame, variable, this._unit(state.next(), scope));
367
377
  }
368
378
  return new VariableNode(frame, variable);
369
379
  }
370
- else if (state.isTildaMark) {
380
+ else if (state.isTilda) {
371
381
  return this._function(state, scope);
372
382
  }
373
383
  else if (state.isWhile) {
@@ -399,16 +409,21 @@ export class Affinirum {
399
409
  state.throwError("variable redefinition");
400
410
  }
401
411
  let argType = Type.Unknown;
402
- if (state.next().isColonSeparator) {
412
+ if (state.next().isColon) {
403
413
  argType = this._type(state.next(), scope);
404
414
  }
405
415
  variables.set(token, new Variable(argType));
406
- if (argType.isArray && state.isVariadicFunction) {
407
- variadic = true;
408
- state.next();
409
- break;
416
+ if (state.isEllipsis) {
417
+ if (argType.isArray) {
418
+ variadic = true;
419
+ state.next();
420
+ break;
421
+ }
422
+ else {
423
+ state.throwError("variadic function argument must be an array type");
424
+ }
410
425
  }
411
- if (!state.isCommaSeparator) {
426
+ if (!state.isComma) {
412
427
  break;
413
428
  }
414
429
  }
@@ -416,10 +431,6 @@ export class Affinirum {
416
431
  frame.ends(state);
417
432
  const args = Array.from(variables.values());
418
433
  state.next().openBraces().next();
419
- if (args.length === 0 && state.isBracesClose) {
420
- state.next();
421
- return new ConstantNode(frame, Constant.EmptyFunction);
422
- }
423
434
  const subnode = this._block(state, scope.subscope(variables));
424
435
  state.closeBraces().next();
425
436
  const value = (...values) => {
@@ -462,7 +473,7 @@ export class Affinirum {
462
473
  _type(state, scope) {
463
474
  if (state.isType) {
464
475
  let type = state.type;
465
- if (state.next().isQuestionMark) {
476
+ if (state.next().isQuestion) {
466
477
  type = type.toOptional();
467
478
  state.next();
468
479
  }
@@ -472,36 +483,29 @@ export class Affinirum {
472
483
  return type;
473
484
  }
474
485
  else if (state.isBracketsOpen) { // array or object type
475
- const itemPropTypes = [];
486
+ const itemKeyTypes = [];
476
487
  let index = 0, colon = false;
477
488
  while (!state.next().isBracketsClose) {
478
- if (state.isColonSeparator) { // default object type
479
- colon = true;
480
- state.next();
481
- break;
482
- }
483
- if (state.isType) {
484
- itemPropTypes.push([index++, this._type(state, scope)]);
485
- }
486
- else if (state.isToken) {
487
- const token = state.token;
489
+ if (state.isLiteral && typeof state.literal.value === "string") {
490
+ const key = state.literal.value;
488
491
  state.next().separateByColon().next();
489
- itemPropTypes.push([token, this._type(state, scope)]);
492
+ itemKeyTypes.push([key, this._type(state, scope)]);
493
+ colon = true;
490
494
  }
491
495
  else {
492
- state.throwError("missing type or property name");
496
+ itemKeyTypes.push([index++, this._type(state, scope)]);
493
497
  }
494
- if (!state.isCommaSeparator) {
498
+ if (!state.isComma) {
495
499
  break;
496
500
  }
497
501
  }
498
502
  state.closeBrackets().next();
499
503
  return colon
500
- ? Type.objectType(Object.fromEntries(itemPropTypes.map(([prop, type]) => [prop, type])))
501
- : Type.arrayType(itemPropTypes.map(([, v]) => v));
504
+ ? Type.objectType(Object.fromEntries(itemKeyTypes.map(([key, type]) => [key, type])))
505
+ : Type.arrayType(itemKeyTypes.map(([, v]) => v));
502
506
  }
503
- else if (state.isTildaMark) { // function type
504
- let retType = undefined;
507
+ else if (state.isTilda) { // function type
508
+ let retType = Type.Unknown;
505
509
  if (!state.next().isParenthesesOpen) {
506
510
  retType = this._type(state, scope);
507
511
  state.openParentheses();
@@ -511,7 +515,7 @@ export class Affinirum {
511
515
  while (!state.next().isParenthesesClose) {
512
516
  const argType = this._type(state, scope);
513
517
  argTypes.push(argType);
514
- if (state.isVariadicFunction) {
518
+ if (state.isEllipsis) {
515
519
  if (argType.isArray) {
516
520
  variadic = true;
517
521
  state.next();
@@ -521,7 +525,7 @@ export class Affinirum {
521
525
  state.throwError("variadic function argument must be an array type");
522
526
  }
523
527
  }
524
- if (!state.isCommaSeparator) {
528
+ if (!state.isComma) {
525
529
  break;
526
530
  }
527
531
  }
package/dst/Constant.d.ts CHANGED
@@ -10,7 +10,4 @@ export declare class Constant {
10
10
  set type(type: Type);
11
11
  get deterministic(): boolean;
12
12
  static Null: Constant;
13
- static EmptyArray: Constant;
14
- static EmptyObject: Constant;
15
- static EmptyFunction: Constant;
16
13
  }
package/dst/Constant.js CHANGED
@@ -21,7 +21,4 @@ export class Constant {
21
21
  return this._deterministic;
22
22
  }
23
23
  static Null = new Constant(undefined);
24
- static EmptyArray = new Constant([]);
25
- static EmptyObject = new Constant({});
26
- static EmptyFunction = new Constant(() => undefined, Type.functionType(undefined, [], false));
27
24
  }
package/dst/Keywords.js CHANGED
@@ -1,15 +1,15 @@
1
1
  export const Keywords = [
2
2
  "true", "false",
3
3
  "null", "void",
4
- "boolean", "bool",
5
- "timestamp", "time",
6
- "float", "flo",
7
- "integer", "int",
8
- "buffer", "buf",
9
- "string", "str",
10
- "array", "arr",
11
- "object", "obj",
12
- "function", "func",
4
+ "boolean",
5
+ "timestamp",
6
+ "float",
7
+ "integer",
8
+ "buffer",
9
+ "string",
10
+ "array",
11
+ "object",
12
+ "function",
13
13
  "variable", "var",
14
14
  "constant", "const",
15
15
  "while",
@@ -29,15 +29,15 @@ export declare class ParserState extends ParserFrame {
29
29
  get isBracketsClose(): boolean;
30
30
  get isBracesOpen(): boolean;
31
31
  get isBracesClose(): boolean;
32
- get isSemicolonSeparator(): boolean;
33
- get isColonSeparator(): boolean;
34
- get isCommaSeparator(): boolean;
35
- get isDotMark(): boolean;
36
- get isQuestionMark(): boolean;
37
- get isTildaMark(): boolean;
38
- get isVariadicFunction(): boolean;
39
- get isVariableDefinition(): boolean;
40
- get isConstantDefinition(): boolean;
32
+ get isSemicolon(): boolean;
33
+ get isColon(): boolean;
34
+ get isComma(): boolean;
35
+ get isDot(): boolean;
36
+ get isQuestion(): boolean;
37
+ get isTilda(): boolean;
38
+ get isEllipsis(): boolean;
39
+ get isVariable(): boolean;
40
+ get isValue(): boolean;
41
41
  get isWhile(): boolean;
42
42
  get isIf(): boolean;
43
43
  get isElse(): boolean;