bare-script 3.3.2 → 3.5.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/lib/model.js CHANGED
@@ -162,6 +162,12 @@ enum BinaryExpressionOperator
162
162
  # Subtraction
163
163
  "-"
164
164
 
165
+ # Bitwise left shift
166
+ "<<"
167
+
168
+ # Bitwise right shift
169
+ ">>"
170
+
165
171
  # Less than or equal
166
172
  "<="
167
173
 
@@ -180,6 +186,15 @@ enum BinaryExpressionOperator
180
186
  # Not equal
181
187
  "!="
182
188
 
189
+ # Bitwise AND
190
+ "&"
191
+
192
+ # Bitwise XOR
193
+ "^"
194
+
195
+ # Bitwise OR
196
+ "|"
197
+
183
198
  # Logical AND
184
199
  "&&"
185
200
 
@@ -206,6 +221,9 @@ enum UnaryExpressionOperator
206
221
  # Logical NOT
207
222
  "!"
208
223
 
224
+ # Bitwise NOT
225
+ "~"
226
+
209
227
 
210
228
  # A function expression
211
229
  struct FunctionExpression
package/lib/parser.js CHANGED
@@ -539,18 +539,23 @@ function parseBinaryExpression(exprText, binLeftExpr = null) {
539
539
 
540
540
  // Binary operator re-order map
541
541
  const binaryReorder = {
542
- '**': new Set(['*', '/', '%', '+', '-', '<=', '<', '>=', '>', '==', '!=', '&&', '||']),
543
- '*': new Set(['+', '-', '<=', '<', '>=', '>', '==', '!=', '&&', '||']),
544
- '/': new Set(['+', '-', '<=', '<', '>=', '>', '==', '!=', '&&', '||']),
545
- '%': new Set(['+', '-', '<=', '<', '>=', '>', '==', '!=', '&&', '||']),
546
- '+': new Set(['<=', '<', '>=', '>', '==', '!=', '&&', '||']),
547
- '-': new Set(['<=', '<', '>=', '>', '==', '!=', '&&', '||']),
548
- '<=': new Set(['==', '!=', '&&', '||']),
549
- '<': new Set(['==', '!=', '&&', '||']),
550
- '>=': new Set(['==', '!=', '&&', '||']),
551
- '>': new Set(['==', '!=', '&&', '||']),
552
- '==': new Set(['&&', '||']),
553
- '!=': new Set(['&&', '||']),
542
+ '**': new Set(['*', '/', '%', '+', '-', '<<', '>>', '<=', '<', '>=', '>', '==', '!=', '&', '^', '|', '&&', '||']),
543
+ '*': new Set(['+', '-', '<<', '>>', '<=', '<', '>=', '>', '==', '!=', '&', '^', '|', '&&', '||']),
544
+ '/': new Set(['+', '-', '<<', '>>', '<=', '<', '>=', '>', '==', '!=', '&', '^', '|', '&&', '||']),
545
+ '%': new Set(['+', '-', '<<', '>>', '<=', '<', '>=', '>', '==', '!=', '&', '^', '|', '&&', '||']),
546
+ '+': new Set(['<<', '>>', '<=', '<', '>=', '>', '==', '!=', '&', '^', '|', '&&', '||']),
547
+ '-': new Set(['<<', '>>', '<=', '<', '>=', '>', '==', '!=', '&', '^', '|', '&&', '||']),
548
+ '<<': new Set(['<=', '<', '>=', '>', '==', '!=', '&', '^', '|', '&&', '||']),
549
+ '>>': new Set(['<=', '<', '>=', '>', '==', '!=', '&', '^', '|', '&&', '||']),
550
+ '<=': new Set(['==', '!=', '&', '^', '|', '&&', '||']),
551
+ '<': new Set(['==', '!=', '&', '^', '|', '&&', '||']),
552
+ '>=': new Set(['==', '!=', '&', '^', '|', '&&', '||']),
553
+ '>': new Set(['==', '!=', '&', '^', '|', '&&', '||']),
554
+ '==': new Set(['&', '^', '|', '&&', '||']),
555
+ '!=': new Set(['&', '^', '|', '&&', '||']),
556
+ '&': new Set(['^', '|', '&&', '||']),
557
+ '^': new Set(['|', '&&', '||']),
558
+ '|': new Set(['&&', '||']),
554
559
  '&&': new Set(['||']),
555
560
  '||': new Set([])
556
561
  };
@@ -570,6 +575,31 @@ function parseUnaryExpression(exprText) {
570
575
  return [{'group': expr}, nextText.slice(matchGroupClose[0].length)];
571
576
  }
572
577
 
578
+ // Number?
579
+ const matchNumber = exprText.match(rExprNumber);
580
+ if (matchNumber !== null) {
581
+ const [numberStr] = matchNumber;
582
+ const number = (numberStr.startsWith('0x') ? parseInt(numberStr, 16) : parseFloat(numberStr));
583
+ const expr = {'number': number};
584
+ return [expr, exprText.slice(matchNumber[0].length)];
585
+ }
586
+
587
+ // String?
588
+ const matchString = exprText.match(rExprString);
589
+ if (matchString !== null) {
590
+ const string = matchString[1].replace(rExprStringEscape, '$1');
591
+ const expr = {'string': string};
592
+ return [expr, exprText.slice(matchString[0].length)];
593
+ }
594
+
595
+ // String (double quotes)?
596
+ const matchStringDouble = exprText.match(rExprStringDouble);
597
+ if (matchStringDouble !== null) {
598
+ const string = matchStringDouble[1].replace(rExprStringDoubleEscape, '$1');
599
+ const expr = {'string': string};
600
+ return [expr, exprText.slice(matchStringDouble[0].length)];
601
+ }
602
+
573
603
  // Unary operator?
574
604
  const matchUnary = exprText.match(rExprUnaryOp);
575
605
  if (matchUnary !== null) {
@@ -621,30 +651,6 @@ function parseUnaryExpression(exprText) {
621
651
  return [fnExpr, argText];
622
652
  }
623
653
 
624
- // Number?
625
- const matchNumber = exprText.match(rExprNumber);
626
- if (matchNumber !== null) {
627
- const number = parseFloat(matchNumber[1]);
628
- const expr = {'number': number};
629
- return [expr, exprText.slice(matchNumber[0].length)];
630
- }
631
-
632
- // String?
633
- const matchString = exprText.match(rExprString);
634
- if (matchString !== null) {
635
- const string = matchString[1].replace(rExprStringEscape, '$1');
636
- const expr = {'string': string};
637
- return [expr, exprText.slice(matchString[0].length)];
638
- }
639
-
640
- // String (double quotes)?
641
- const matchStringDouble = exprText.match(rExprStringDouble);
642
- if (matchStringDouble !== null) {
643
- const string = matchStringDouble[1].replace(rExprStringDoubleEscape, '$1');
644
- const expr = {'string': string};
645
- return [expr, exprText.slice(matchStringDouble[0].length)];
646
- }
647
-
648
654
  // Variable?
649
655
  const matchVariable = exprText.match(rExprVariable);
650
656
  if (matchVariable !== null) {
@@ -665,14 +671,14 @@ function parseUnaryExpression(exprText) {
665
671
 
666
672
 
667
673
  // BareScript expression regex
668
- const rExprBinaryOp = /^\s*(\*\*|\*|\/|%|\+|-|<=|<|>=|>|==|!=|&&|\|\|)/;
669
- const rExprUnaryOp = /^\s*(!|-)/;
674
+ const rExprBinaryOp = /^\s*(\*\*|\*|\/|%|\+|-|<<|>>|<=|<|>=|>|==|!=|&&|\|\||&|\^|\|)/;
675
+ const rExprUnaryOp = /^\s*(!|-|~)/;
670
676
  const rExprFunctionOpen = /^\s*([A-Za-z_]\w+)\s*\(/;
671
677
  const rExprFunctionSeparator = /^\s*,/;
672
678
  const rExprFunctionClose = /^\s*\)/;
673
679
  const rExprGroupOpen = /^\s*\(/;
674
680
  const rExprGroupClose = /^\s*\)/;
675
- const rExprNumber = /^\s*([+-]?\d+(?:\.\d*)?(?:e[+-]\d+)?)/;
681
+ const rExprNumber = /^\s*(0x[A-Fa-f0-9]+|[+-]?\d+(?:\.\d*)?(?:e[+-]?\d+)?)/;
676
682
  const rExprString = /^\s*'((?:\\\\|\\'|[^'])*)'/;
677
683
  const rExprStringEscape = /\\([\\'])/g;
678
684
  const rExprStringDouble = /^\s*"((?:\\\\|\\"|[^"])*)"/;
package/lib/runtime.js CHANGED
@@ -300,12 +300,37 @@ export function evaluateExpression(expr, options = null, locals = null, builtins
300
300
  if (typeof leftValue === 'number' && typeof rightValue === 'number') {
301
301
  return leftValue % rightValue;
302
302
  }
303
- } else {
304
- // binOp === '**'
303
+ } else if (binOp === '**') {
305
304
  // number ** number
306
305
  if (typeof leftValue === 'number' && typeof rightValue === 'number') {
307
306
  return leftValue ** rightValue;
308
307
  }
308
+ } else if (binOp === '&') {
309
+ if (typeof leftValue === 'number' && Math.floor(leftValue) === leftValue &&
310
+ typeof rightValue === 'number' && Math.floor(rightValue) === rightValue) {
311
+ return leftValue & rightValue;
312
+ }
313
+ } else if (binOp === '|') {
314
+ if (typeof leftValue === 'number' && Math.floor(leftValue) === leftValue &&
315
+ typeof rightValue === 'number' && Math.floor(rightValue) === rightValue) {
316
+ return leftValue | rightValue;
317
+ }
318
+ } else if (binOp === '^') {
319
+ if (typeof leftValue === 'number' && Math.floor(leftValue) === leftValue &&
320
+ typeof rightValue === 'number' && Math.floor(rightValue) === rightValue) {
321
+ return leftValue ^ rightValue;
322
+ }
323
+ } else if (binOp === '<<') {
324
+ if (typeof leftValue === 'number' && Math.floor(leftValue) === leftValue &&
325
+ typeof rightValue === 'number' && Math.floor(rightValue) === rightValue) {
326
+ return leftValue << rightValue;
327
+ }
328
+ } else {
329
+ // if (binOp === '>>')
330
+ if (typeof leftValue === 'number' && Math.floor(leftValue) === leftValue &&
331
+ typeof rightValue === 'number' && Math.floor(rightValue) === rightValue) {
332
+ return leftValue >> rightValue;
333
+ }
309
334
  }
310
335
 
311
336
  // Invalid operation values
@@ -318,8 +343,15 @@ export function evaluateExpression(expr, options = null, locals = null, builtins
318
343
  const value = evaluateExpression(expr.unary.expr, options, locals, builtins);
319
344
  if (unaryOp === '!') {
320
345
  return !valueBoolean(value);
321
- } else if (unaryOp === '-' && typeof value === 'number') {
322
- return -value;
346
+ } else if (unaryOp === '-') {
347
+ if (typeof value === 'number') {
348
+ return -value;
349
+ }
350
+ } else {
351
+ // if (unaryOp === '~'
352
+ if (typeof value === 'number' && Math.floor(value) === value) {
353
+ return ~value;
354
+ }
323
355
  }
324
356
 
325
357
  // Invalid operation value
@@ -371,12 +371,37 @@ export async function evaluateExpressionAsync(expr, options = null, locals = nul
371
371
  if (typeof leftValue === 'number' && typeof rightValue === 'number') {
372
372
  return leftValue % rightValue;
373
373
  }
374
- } else {
375
- // binOp === '**'
374
+ } else if (binOp === '**') {
376
375
  // number ** number
377
376
  if (typeof leftValue === 'number' && typeof rightValue === 'number') {
378
377
  return leftValue ** rightValue;
379
378
  }
379
+ } else if (binOp === '&') {
380
+ if (typeof leftValue === 'number' && Math.floor(leftValue) === leftValue &&
381
+ typeof rightValue === 'number' && Math.floor(rightValue) === rightValue) {
382
+ return leftValue & rightValue;
383
+ }
384
+ } else if (binOp === '|') {
385
+ if (typeof leftValue === 'number' && Math.floor(leftValue) === leftValue &&
386
+ typeof rightValue === 'number' && Math.floor(rightValue) === rightValue) {
387
+ return leftValue | rightValue;
388
+ }
389
+ } else if (binOp === '^') {
390
+ if (typeof leftValue === 'number' && Math.floor(leftValue) === leftValue &&
391
+ typeof rightValue === 'number' && Math.floor(rightValue) === rightValue) {
392
+ return leftValue ^ rightValue;
393
+ }
394
+ } else if (binOp === '<<') {
395
+ if (typeof leftValue === 'number' && Math.floor(leftValue) === leftValue &&
396
+ typeof rightValue === 'number' && Math.floor(rightValue) === rightValue) {
397
+ return leftValue << rightValue;
398
+ }
399
+ } else {
400
+ // if (binOp === '>>')
401
+ if (typeof leftValue === 'number' && Math.floor(leftValue) === leftValue &&
402
+ typeof rightValue === 'number' && Math.floor(rightValue) === rightValue) {
403
+ return leftValue >> rightValue;
404
+ }
380
405
  }
381
406
 
382
407
  // Invalid operation values
@@ -389,8 +414,15 @@ export async function evaluateExpressionAsync(expr, options = null, locals = nul
389
414
  const value = await evaluateExpressionAsync(expr.unary.expr, options, locals, builtins);
390
415
  if (unaryOp === '!') {
391
416
  return !valueBoolean(value);
392
- } else if (unaryOp === '-' && typeof value === 'number') {
393
- return -value;
417
+ } else if (unaryOp === '-') {
418
+ if (typeof value === 'number') {
419
+ return -value;
420
+ }
421
+ } else {
422
+ // if (unaryOp === '~'
423
+ if (typeof value === 'number' && Math.floor(value) === value) {
424
+ return ~value;
425
+ }
394
426
  }
395
427
 
396
428
  // Invalid operation value
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "bare-script",
4
- "version": "3.3.2",
4
+ "version": "3.5.0",
5
5
  "description": "BareScript; a lightweight scripting and expression language",
6
6
  "keywords": [
7
7
  "expression",
@@ -31,7 +31,7 @@
31
31
  },
32
32
  "devDependencies": {
33
33
  "c8": "~10.1",
34
- "eslint": "~9.28",
34
+ "eslint": "~9.35",
35
35
  "jsdoc": "~4.0"
36
36
  }
37
37
  }