simple-graph-query 2.7.2 → 2.8.2
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.
|
@@ -48590,7 +48590,7 @@ function bitwidthWraparound(value, bitwidth) {
|
|
|
48590
48590
|
// this is a list of forge builtin functions we currently support; add to this
|
|
48591
48591
|
// list as we support more
|
|
48592
48592
|
const SUPPORTED_BINARY_BUILTINS = ["add", "subtract", "multiply", "divide", "remainder"];
|
|
48593
|
-
const SUPPORTED_UNARY_BUILTINS = ["abs", "sign"];
|
|
48593
|
+
const SUPPORTED_UNARY_BUILTINS = ["abs", "sign", "floor", "ceil"];
|
|
48594
48594
|
const SUPPORTED_SET_BUILTINS = ["min", "max"];
|
|
48595
48595
|
exports.SUPPORTED_BUILTINS = SUPPORTED_BINARY_BUILTINS.concat(SUPPORTED_UNARY_BUILTINS, SUPPORTED_SET_BUILTINS);
|
|
48596
48596
|
/**
|
|
@@ -48987,6 +48987,46 @@ class ForgeExprEvaluator extends AbstractParseTreeVisitor_1.AbstractParseTreeVis
|
|
|
48987
48987
|
varNames.push(varName);
|
|
48988
48988
|
quantifiedSets.push(varQuantifiedSets[varName]);
|
|
48989
48989
|
}
|
|
48990
|
+
// `sum <decls> | <intExpr>`: accumulate the numeric body over every
|
|
48991
|
+
// binding of the quantified variables. Unlike the boolean quantifiers
|
|
48992
|
+
// below, the body evaluates to a number, so this needs its own loop --
|
|
48993
|
+
// and it must not use the boolean numeric-comparison optimization, which
|
|
48994
|
+
// skips body evaluation entirely.
|
|
48995
|
+
if (ctx.quant().SUM_TOK()) {
|
|
48996
|
+
const sumCombinations = getCombinations(quantifiedSets);
|
|
48997
|
+
const sumEnv = { env: {}, type: "quantDecl" };
|
|
48998
|
+
this.environmentStack.push(sumEnv);
|
|
48999
|
+
let total = 0;
|
|
49000
|
+
for (const tuple of sumCombinations) {
|
|
49001
|
+
if (isDisjoint) {
|
|
49002
|
+
const seen = new Set();
|
|
49003
|
+
let tupleDisjoint = true;
|
|
49004
|
+
for (const val of tuple) {
|
|
49005
|
+
if (seen.has(val)) {
|
|
49006
|
+
tupleDisjoint = false;
|
|
49007
|
+
break;
|
|
49008
|
+
}
|
|
49009
|
+
seen.add(val);
|
|
49010
|
+
}
|
|
49011
|
+
if (!tupleDisjoint) {
|
|
49012
|
+
continue;
|
|
49013
|
+
}
|
|
49014
|
+
}
|
|
49015
|
+
for (let j = 0; j < varNames.length; j++) {
|
|
49016
|
+
sumEnv.env[varNames[j]] = tuple[j];
|
|
49017
|
+
}
|
|
49018
|
+
const bodyValue = this.visit(barExpr);
|
|
49019
|
+
const bodyNumber = extractNumber(bodyValue);
|
|
49020
|
+
if (bodyNumber === undefined) {
|
|
49021
|
+
this.environmentStack.pop();
|
|
49022
|
+
throw new Error("Expected the expression after the bar in a `sum` to evaluate to a number!");
|
|
49023
|
+
}
|
|
49024
|
+
total += bodyNumber;
|
|
49025
|
+
}
|
|
49026
|
+
this.environmentStack.pop();
|
|
49027
|
+
this.cacheResult(ctx, freeVarsKey, total);
|
|
49028
|
+
return total;
|
|
49029
|
+
}
|
|
48990
49030
|
// Try to optimize numeric comparisons
|
|
48991
49031
|
let product;
|
|
48992
49032
|
let useOptimizedPath = false;
|
|
@@ -49133,7 +49173,8 @@ class ForgeExprEvaluator extends AbstractParseTreeVisitor_1.AbstractParseTreeVis
|
|
|
49133
49173
|
return value;
|
|
49134
49174
|
}
|
|
49135
49175
|
}
|
|
49136
|
-
//
|
|
49176
|
+
// NOTE: SUM_TOK is handled above (it returns a number, not a boolean),
|
|
49177
|
+
// before this boolean-quantifier result logic.
|
|
49137
49178
|
}
|
|
49138
49179
|
// TODO: fix this!
|
|
49139
49180
|
const childrenResults = this.visitChildren(ctx);
|
|
@@ -49461,25 +49502,21 @@ class ForgeExprEvaluator extends AbstractParseTreeVisitor_1.AbstractParseTreeVis
|
|
|
49461
49502
|
break;
|
|
49462
49503
|
case "in":
|
|
49463
49504
|
case "ni": {
|
|
49464
|
-
|
|
49465
|
-
//
|
|
49466
|
-
//
|
|
49467
|
-
|
|
49468
|
-
|
|
49469
|
-
|
|
49470
|
-
|
|
49471
|
-
|
|
49472
|
-
|
|
49473
|
-
|
|
49474
|
-
|
|
49475
|
-
|
|
49476
|
-
|
|
49477
|
-
|
|
49478
|
-
|
|
49479
|
-
else {
|
|
49480
|
-
// left is a tuple array but right is a single value, so false
|
|
49481
|
-
membershipResult = false;
|
|
49482
|
-
}
|
|
49505
|
+
// In Alloy/Forge everything is a relation, and a scalar is just a
|
|
49506
|
+
// singleton set. Lift any scalar operand to a singleton tuple so `in`
|
|
49507
|
+
// is uniformly subset:
|
|
49508
|
+
// a in b ({a} ⊆ {b}) -> equality when both are scalars
|
|
49509
|
+
// a in {..} ({a} ⊆ set) -> membership
|
|
49510
|
+
// {..} in b (set ⊆ {b}) -> subset of a singleton
|
|
49511
|
+
// isTupleArraySubset already returns true for equal sets and for an
|
|
49512
|
+
// empty left-hand set, so a single subset check covers every case.
|
|
49513
|
+
const leftSet = isSingleValue(leftChildValue)
|
|
49514
|
+
? [[leftChildValue]]
|
|
49515
|
+
: leftChildValue;
|
|
49516
|
+
const rightSet = isSingleValue(rightChildValue)
|
|
49517
|
+
? [[rightChildValue]]
|
|
49518
|
+
: rightChildValue;
|
|
49519
|
+
const membershipResult = isTupleArraySubset(leftSet, rightSet);
|
|
49483
49520
|
results = ctx.compareOp()?.text === "ni" ? !membershipResult : membershipResult;
|
|
49484
49521
|
break;
|
|
49485
49522
|
}
|
|
@@ -50367,7 +50404,7 @@ class ForgeExprEvaluator extends AbstractParseTreeVisitor_1.AbstractParseTreeVis
|
|
|
50367
50404
|
result = arg1 * arg2;
|
|
50368
50405
|
break;
|
|
50369
50406
|
case "divide":
|
|
50370
|
-
result =
|
|
50407
|
+
result = arg1 / arg2; // Real (floating-point) division
|
|
50371
50408
|
break;
|
|
50372
50409
|
case "remainder":
|
|
50373
50410
|
result = arg1 % arg2;
|
|
@@ -50378,17 +50415,17 @@ class ForgeExprEvaluator extends AbstractParseTreeVisitor_1.AbstractParseTreeVis
|
|
|
50378
50415
|
return result;
|
|
50379
50416
|
}
|
|
50380
50417
|
evaluateUnaryOperation(operation, args) {
|
|
50381
|
-
|
|
50418
|
+
const v = extractNumber(args);
|
|
50419
|
+
if (v === undefined) {
|
|
50382
50420
|
throw new Error(`Expected 1 argument for ${operation} that evaluates to a number.`);
|
|
50383
50421
|
}
|
|
50384
|
-
let v = args;
|
|
50385
50422
|
// Possible unary operations:
|
|
50386
|
-
//abs[]:
|
|
50387
|
-
//sign[]:
|
|
50423
|
+
//abs[]: returns the absolute value of value
|
|
50424
|
+
//sign[]: returns 1 if value is > 0, 0 if value is 0, and -1 if value is < 0
|
|
50425
|
+
//floor[]: rounds value down to the nearest integer
|
|
50426
|
+
//ceil[]: rounds value up to the nearest integer
|
|
50388
50427
|
if (operation === "abs") {
|
|
50389
|
-
|
|
50390
|
-
// Now adjust to the bitwidth
|
|
50391
|
-
return res;
|
|
50428
|
+
return Math.abs(v);
|
|
50392
50429
|
}
|
|
50393
50430
|
else if (operation === "sign") {
|
|
50394
50431
|
if (v > 0) {
|
|
@@ -50401,6 +50438,12 @@ class ForgeExprEvaluator extends AbstractParseTreeVisitor_1.AbstractParseTreeVis
|
|
|
50401
50438
|
return 0;
|
|
50402
50439
|
}
|
|
50403
50440
|
}
|
|
50441
|
+
else if (operation === "floor") {
|
|
50442
|
+
return Math.floor(v);
|
|
50443
|
+
}
|
|
50444
|
+
else if (operation === "ceil") {
|
|
50445
|
+
return Math.ceil(v);
|
|
50446
|
+
}
|
|
50404
50447
|
else {
|
|
50405
50448
|
throw new Error(`Unsupported operation: ${operation}`);
|
|
50406
50449
|
}
|
package/package.json
CHANGED