@nudojs/core 1.4.0 → 1.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.
@@ -1757,6 +1757,10 @@ function joinValues(a, b) {
1757
1757
  }
1758
1758
  return makeSum(a, b);
1759
1759
  }
1760
+ const hasPred = (x) => !!x.pred && x.pred.op !== "true";
1761
+ if (hasPred(a) || hasPred(b)) {
1762
+ return makeSum(a, b);
1763
+ }
1760
1764
  return abs(a.shape, void 0, void 0, confJoin(confJoin(a.conf, b.conf), "path"));
1761
1765
  }
1762
1766
  return makeSum(a, b);
@@ -3734,8 +3738,320 @@ function migrateInvariants(from, to) {
3734
3738
  if (f) propFlagsTable.set(to, new Map(f));
3735
3739
  }
3736
3740
 
3737
- // src/algebra/builtins/shared.ts
3741
+ // src/algebra/exec/runtime/state.ts
3742
+ import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
3743
+
3744
+ // src/algebra/containers.ts
3745
+ var TUPLE_LITERAL_CAP = 8;
3746
+ function shouldWidenArrayLiteral(n) {
3747
+ return n > TUPLE_LITERAL_CAP;
3748
+ }
3749
+ var TUPLE_MATERIALIZE_CAP = 4096;
3750
+ function widenedArrayConf() {
3751
+ return "path";
3752
+ }
3753
+
3754
+ // src/algebra/exec/runtime/state.ts
3755
+ function writeInPlace(target, next) {
3756
+ target.shape = next.shape;
3757
+ target.conf = next.conf;
3758
+ target.term = void 0;
3759
+ target.pred = void 0;
3760
+ return target;
3761
+ }
3762
+ function clearStaleTermPred(v2) {
3763
+ v2.term = void 0;
3764
+ v2.pred = void 0;
3765
+ }
3766
+ var phi = pTrue;
3767
+ function currentExecPhi() {
3768
+ return phi;
3769
+ }
3770
+ function withExecPhi(p, body) {
3771
+ const prev = phi;
3772
+ phi = p;
3773
+ try {
3774
+ return body();
3775
+ } finally {
3776
+ phi = prev;
3777
+ }
3778
+ }
3738
3779
  var noBody = { type: "BlockStatement", body: [], directives: [] };
3780
+ function asAbsVal(v2) {
3781
+ if (v2 && typeof v2 === "object" && "shape" in v2) return v2;
3782
+ if (typeof v2 === "function") {
3783
+ const n = Math.max(0, v2.length);
3784
+ const params = Array.from({ length: n }, (_, i) => `arg${i}`);
3785
+ return absFunction(params, {
3786
+ body: noBody,
3787
+ // 与 $fnVal / $callNamed 同边界:callee 的 NudoReturn 不得冒泡成 caller
3788
+ apply: (args) => callAtFunctionBoundary(() => v2(...args))
3789
+ });
3790
+ }
3791
+ return $lit(v2);
3792
+ }
3793
+ function callAtFunctionBoundary(body) {
3794
+ let forwarded = [];
3795
+ try {
3796
+ return runWithLoopExits(() => {
3797
+ try {
3798
+ const r = body();
3799
+ forwarded = takeThrowExits();
3800
+ return r;
3801
+ } catch (e) {
3802
+ forwarded = takeThrowExits();
3803
+ if (isNudoReturn(e)) return e.absValue;
3804
+ throw e;
3805
+ }
3806
+ });
3807
+ } finally {
3808
+ for (const x of forwarded) pushThrowExit(x);
3809
+ }
3810
+ }
3811
+ function $fnVal(params, impl, opts) {
3812
+ return absFunction(params, {
3813
+ body: noBody,
3814
+ // bindThis(对象方法):receiver 走首参注入,无宿主 this;
3815
+ // 非方法 fn:宿主 this 传递(call/apply/bind 的 thisArg 经 $rawThis 进入函数体)
3816
+ apply: opts?.bindThis ? (args) => callAtFunctionBoundary(() => impl(...args)) : (args, thisVal) => callAtFunctionBoundary(() => impl.apply(thisVal, args)),
3817
+ ...opts?.bindThis ? { bindThis: true } : {}
3818
+ });
3819
+ }
3820
+ function $rawThis(v2) {
3821
+ if (v2 === void 0 || v2 === globalThis) return $lit(void 0);
3822
+ if (v2 && typeof v2 === "object" && "shape" in v2) return v2;
3823
+ return $lit(v2);
3824
+ }
3825
+ function throwStrictWrite() {
3826
+ throw new NudoThrow(errorTypeAbs("TypeError"));
3827
+ }
3828
+ function $throwConstAssign() {
3829
+ throw new NudoThrow(errorTypeAbs("TypeError"));
3830
+ }
3831
+ function $litTruth(a) {
3832
+ return litTruth(a);
3833
+ }
3834
+ function $lit(v2) {
3835
+ if (v2 && typeof v2 === "object" && "shape" in v2 && "conf" in v2) {
3836
+ return v2;
3837
+ }
3838
+ return litAbsFromJs(v2);
3839
+ }
3840
+ function litAbsFromJs(v2, depth = 0) {
3841
+ if (v2 === null || v2 === void 0) {
3842
+ return abs({ k: "unknown" }, { op: "lit", value: v2 }, pTrue, "exact");
3843
+ }
3844
+ const t = typeof v2;
3845
+ if (t === "number" || t === "string" || t === "boolean" || t === "bigint") {
3846
+ return abs(
3847
+ { k: "prim", type: t },
3848
+ { op: "lit", value: v2 },
3849
+ pTrue,
3850
+ "exact"
3851
+ );
3852
+ }
3853
+ if (depth < 8) {
3854
+ if (Array.isArray(v2)) {
3855
+ const els = v2.map((x) => litAbsFromJs(x, depth + 1));
3856
+ if (shouldWidenArrayLiteral(els.length)) {
3857
+ return abs(
3858
+ { k: "arr", element: els.reduce((x, y) => joinAbs(x, y)) },
3859
+ void 0,
3860
+ void 0,
3861
+ widenedArrayConf()
3862
+ );
3863
+ }
3864
+ return abs({ k: "tuple", elements: els }, void 0, void 0, "exact");
3865
+ }
3866
+ if (t === "object") {
3867
+ const proto = Object.getPrototypeOf(v2);
3868
+ if (proto === Object.prototype || proto === null) {
3869
+ const slots = {};
3870
+ for (const [k, val] of Object.entries(v2)) {
3871
+ Object.defineProperty(slots, k, {
3872
+ value: { value: litAbsFromJs(val, depth + 1) },
3873
+ enumerable: true,
3874
+ writable: true,
3875
+ configurable: true
3876
+ });
3877
+ }
3878
+ return objOf(slots);
3879
+ }
3880
+ }
3881
+ }
3882
+ return unknown;
3883
+ }
3884
+ function litTruth(a) {
3885
+ if (a.term?.op === "lit") {
3886
+ return Boolean(a.term.value);
3887
+ }
3888
+ switch (a.shape.k) {
3889
+ case "obj":
3890
+ case "arr":
3891
+ case "tuple":
3892
+ case "fn":
3893
+ case "brand":
3894
+ case "eff":
3895
+ return true;
3896
+ case "prim":
3897
+ return a.shape.type === "symbol" ? true : void 0;
3898
+ case "never":
3899
+ return false;
3900
+ default:
3901
+ return void 0;
3902
+ }
3903
+ }
3904
+ function isDefinitelyTrue(a) {
3905
+ return litTruth(a) === true;
3906
+ }
3907
+ function isDefinitelyFalse(a) {
3908
+ const t = litTruth(a);
3909
+ if (t === false) return true;
3910
+ if (a.shape.k === "never") return true;
3911
+ return false;
3912
+ }
3913
+ function undef() {
3914
+ return abs({ k: "unknown" }, { op: "lit", value: void 0 }, pTrue, "exact");
3915
+ }
3916
+ var loopExitsAls = new AsyncLocalStorage2();
3917
+ var throwExitsAls = new AsyncLocalStorage2();
3918
+ var tryMarksAls = new AsyncLocalStorage2();
3919
+ var softFrameActiveAls = new AsyncLocalStorage2();
3920
+ function runWithLoopExits(body) {
3921
+ return loopExitsAls.run(
3922
+ [],
3923
+ () => throwExitsAls.run(
3924
+ [],
3925
+ () => tryMarksAls.run([], () => softFrameActiveAls.run([], body))
3926
+ )
3927
+ );
3928
+ }
3929
+ function takeLoopExits() {
3930
+ return loopExitsAls.getStore() ?? [];
3931
+ }
3932
+ function takeThrowExits() {
3933
+ return throwExitsAls.getStore() ?? [];
3934
+ }
3935
+ function pushLoopExit(v2) {
3936
+ loopExitsAls.getStore()?.push(v2);
3937
+ }
3938
+ function pushThrowExit(v2) {
3939
+ throwExitsAls.getStore()?.push(v2);
3940
+ }
3941
+ function $pushLoopExit(v2) {
3942
+ pushLoopExit(v2);
3943
+ }
3944
+ function $tryMark() {
3945
+ $tryMarkSoft();
3946
+ softFrameActiveAls.getStore()?.push(true);
3947
+ const store = throwExitsAls.getStore();
3948
+ const m = store?.length ?? 0;
3949
+ tryMarksAls.getStore()?.push(m);
3950
+ return m;
3951
+ }
3952
+ function $tryCurrentMark() {
3953
+ const stack = tryMarksAls.getStore();
3954
+ return stack && stack.length > 0 ? stack[stack.length - 1] : 0;
3955
+ }
3956
+ function $tryPopMark() {
3957
+ tryMarksAls.getStore()?.pop();
3958
+ const soft = softFrameActiveAls.getStore();
3959
+ if (soft && soft.length > 0) {
3960
+ if (soft[soft.length - 1]) $tryReleaseSoftOut();
3961
+ soft.pop();
3962
+ }
3963
+ }
3964
+ function $tryTakeSince(mark) {
3965
+ const store = throwExitsAls.getStore();
3966
+ if (!store) return [];
3967
+ return store.splice(Math.min(mark, store.length));
3968
+ }
3969
+ function peekThrowExitsSince(mark) {
3970
+ const store = throwExitsAls.getStore();
3971
+ if (!store) return [];
3972
+ return store.slice(Math.min(mark, store.length));
3973
+ }
3974
+ function throwExitsMark() {
3975
+ return throwExitsAls.getStore()?.length ?? 0;
3976
+ }
3977
+ function $tryDigestSoftCatch() {
3978
+ const soft = softFrameActiveAls.getStore();
3979
+ if (!soft || soft.length === 0 || !soft[soft.length - 1]) return;
3980
+ $tryDigestSoft();
3981
+ soft[soft.length - 1] = false;
3982
+ }
3983
+ function $tryReleaseSoftCatch() {
3984
+ const soft = softFrameActiveAls.getStore();
3985
+ if (!soft || soft.length === 0 || !soft[soft.length - 1]) return;
3986
+ $tryReleaseSoft();
3987
+ soft[soft.length - 1] = false;
3988
+ }
3989
+ function $tryDetachSoftCatch() {
3990
+ const soft = softFrameActiveAls.getStore();
3991
+ if (!soft || soft.length === 0 || !soft[soft.length - 1]) return [];
3992
+ const effects = popMayThrowFrame(false);
3993
+ soft[soft.length - 1] = false;
3994
+ return effects;
3995
+ }
3996
+ function $tryDiscardSoft(_effects) {
3997
+ }
3998
+ function $tryOrphanSoft(effects) {
3999
+ orphanMayThrowEffects(effects);
4000
+ }
4001
+ function $tryReleaseSoftOut() {
4002
+ const soft = softFrameActiveAls.getStore();
4003
+ if (!soft || soft.length === 0 || !soft[soft.length - 1]) return;
4004
+ $tryReleaseSoft();
4005
+ soft[soft.length - 1] = false;
4006
+ }
4007
+ var NudoReturn = class extends Error {
4008
+ absValue;
4009
+ constructor(absValue) {
4010
+ super("nudo:return");
4011
+ this.name = "NudoReturn";
4012
+ this.absValue = absValue;
4013
+ }
4014
+ };
4015
+ function isNudoReturn(e) {
4016
+ return e instanceof NudoReturn;
4017
+ }
4018
+ function $loopReturn(v2) {
4019
+ throw new NudoReturn(v2);
4020
+ }
4021
+ var NudoLoopSignal = class extends Error {
4022
+ kind;
4023
+ label;
4024
+ constructor(kind, label) {
4025
+ super("nudo:loop");
4026
+ this.name = "NudoLoopSignal";
4027
+ this.kind = kind;
4028
+ this.label = label;
4029
+ }
4030
+ };
4031
+ function $loopBreak(label) {
4032
+ throw new NudoLoopSignal("break", label || void 0);
4033
+ }
4034
+ function $loopContinue(label) {
4035
+ throw new NudoLoopSignal("continue", label || void 0);
4036
+ }
4037
+ function loopSignalMatches(e, label) {
4038
+ return e.label === void 0 || e.label === label;
4039
+ }
4040
+ function isNudoBreak(e, label) {
4041
+ return e instanceof NudoLoopSignal && e.kind === "break" && loopSignalMatches(e, label);
4042
+ }
4043
+ function isNudoContinue(e, label) {
4044
+ return e instanceof NudoLoopSignal && e.kind === "continue" && loopSignalMatches(e, label);
4045
+ }
4046
+ function $isBreakTo(e, label) {
4047
+ return e instanceof NudoLoopSignal && e.kind === "break" && e.label === label;
4048
+ }
4049
+ function $rethrowIfNudoReturn(e) {
4050
+ if (isNudoReturn(e)) throw e;
4051
+ }
4052
+
4053
+ // src/algebra/builtins/shared.ts
4054
+ var noBody2 = { type: "BlockStatement", body: [], directives: [] };
3739
4055
  function numPrim(conf = "path") {
3740
4056
  return abs({ k: "prim", type: "number" }, void 0, void 0, conf);
3741
4057
  }
@@ -3770,13 +4086,199 @@ function coerceMathArg(a) {
3770
4086
  if (v2 === void 0) return void 0;
3771
4087
  return "throw";
3772
4088
  }
3773
- function mathMethod(name) {
3774
- if (!Object.hasOwn(Math, name)) return void 0;
3775
- const impl = Math[name];
3776
- return typeof impl === "function" ? impl : void 0;
4089
+ function mathMethod(name) {
4090
+ if (!Object.hasOwn(Math, name)) return void 0;
4091
+ const impl = Math[name];
4092
+ return typeof impl === "function" ? impl : void 0;
4093
+ }
4094
+ function isNonNaN(a, phi2) {
4095
+ if (a.term?.op === "lit") {
4096
+ return typeof a.term.value === "number" && !Number.isNaN(a.term.value);
4097
+ }
4098
+ const hasNonNaNFact = (p) => {
4099
+ if (!p) return false;
4100
+ if (p.op === "and") return p.args.some(hasNonNaNFact);
4101
+ if (p.op === "assumeFinite") {
4102
+ return !!a.term && termEquals(p.t, a.term);
4103
+ }
4104
+ if (p.op === "ne") {
4105
+ if (p.b.op === "lit" && typeof p.b.value === "number" && Number.isNaN(p.b.value) && a.term && termEquals(p.a, a.term)) {
4106
+ return true;
4107
+ }
4108
+ }
4109
+ if (p.op === "gt" || p.op === "ge" || p.op === "lt" || p.op === "le") {
4110
+ if (a.term && (termEquals(p.a, a.term) || termEquals(p.b, a.term))) return true;
4111
+ }
4112
+ return false;
4113
+ };
4114
+ if (hasNonNaNFact(a.pred)) return true;
4115
+ if (a.term?.op === "var") {
4116
+ const id = a.term.id;
4117
+ const conjs = phi2.op === "and" ? phi2.args : [phi2];
4118
+ for (const p of conjs) {
4119
+ if (p.op === "assumeFinite" && p.t.op === "var" && p.t.id === id) {
4120
+ return true;
4121
+ }
4122
+ if (p.op === "ne") {
4123
+ const b = p.b;
4124
+ if (b.op === "lit" && typeof b.value === "number" && Number.isNaN(b.value) && p.a.op === "var" && p.a.id === id) {
4125
+ return true;
4126
+ }
4127
+ }
4128
+ if (p.op === "gt" || p.op === "ge" || p.op === "lt" || p.op === "le") {
4129
+ const sides = [p.a, p.b];
4130
+ if (sides.some((t) => t.op === "var" && t.id === id) && sides.some((t) => t.op === "lit" && typeof t.value === "number")) {
4131
+ return true;
4132
+ }
4133
+ }
4134
+ }
4135
+ }
4136
+ return false;
4137
+ }
4138
+ function ieeeBoundNum(n) {
4139
+ return Number.isFinite(n) || n === Infinity || n === -Infinity ? n : void 0;
4140
+ }
4141
+ function loMin(a, b) {
4142
+ if (a.lo === void 0 || b.lo === void 0) return void 0;
4143
+ if (b.lo.value < a.lo.value) return b.lo;
4144
+ if (b.lo.value === a.lo.value && b.lo.strict && !a.lo.strict) return b.lo;
4145
+ return a.lo;
4146
+ }
4147
+ function loMax(a, b) {
4148
+ if (a.lo === void 0) return b.lo;
4149
+ if (b.lo === void 0) return a.lo;
4150
+ if (b.lo.value > a.lo.value) return b.lo;
4151
+ if (b.lo.value === a.lo.value && b.lo.strict && !a.lo.strict) return b.lo;
4152
+ return a.lo;
4153
+ }
4154
+ function hiMin(a, b) {
4155
+ if (a.hi === void 0) return b.hi;
4156
+ if (b.hi === void 0) return a.hi;
4157
+ if (b.hi.value < a.hi.value) return b.hi;
4158
+ if (b.hi.value === a.hi.value && b.hi.strict && !a.hi.strict) return b.hi;
4159
+ return a.hi;
4160
+ }
4161
+ function hiMax(a, b) {
4162
+ if (a.hi === void 0 || b.hi === void 0) return void 0;
4163
+ if (b.hi.value > a.hi.value) return b.hi;
4164
+ if (b.hi.value === a.hi.value && b.hi.strict && !a.hi.strict) return b.hi;
4165
+ return a.hi;
4166
+ }
4167
+ function boundsToPred(t, b) {
4168
+ const facts = [];
4169
+ if (b.lo !== void 0) {
4170
+ const v2 = ieeeBoundNum(b.lo.value);
4171
+ if (v2 !== void 0) {
4172
+ facts.push(b.lo.strict ? { op: "gt", a: t, b: lit(v2) } : { op: "ge", a: t, b: lit(v2) });
4173
+ }
4174
+ }
4175
+ if (b.hi !== void 0) {
4176
+ const v2 = ieeeBoundNum(b.hi.value);
4177
+ if (v2 !== void 0) {
4178
+ facts.push(b.hi.strict ? { op: "lt", a: t, b: lit(v2) } : { op: "le", a: t, b: lit(v2) });
4179
+ }
4180
+ }
4181
+ if (facts.length === 0) return void 0;
4182
+ return facts.length === 1 ? facts[0] : and(...facts);
4183
+ }
4184
+ function minMaxAbs(name, args) {
4185
+ const phi2 = currentExecPhi();
4186
+ const empty = {};
4187
+ let acc = empty;
4188
+ const termArgs = args.map(
4189
+ (a, i) => a.term ?? app(`arg${i}`, [])
4190
+ );
4191
+ const term = simplifyTerm(app(`Math.${name}`, termArgs));
4192
+ let first = true;
4193
+ let mayNaN = false;
4194
+ for (const a of args) {
4195
+ if (!isNonNaN(a, phi2)) mayNaN = true;
4196
+ const b = numericBounds(a, phi2) ?? {};
4197
+ if (first) {
4198
+ acc = { lo: b.lo, hi: b.hi };
4199
+ first = false;
4200
+ continue;
4201
+ }
4202
+ if (name === "min") {
4203
+ acc = { lo: loMin(acc, b), hi: hiMin(acc, b) };
4204
+ } else {
4205
+ acc = { lo: loMax(acc, b), hi: hiMax(acc, b) };
4206
+ }
4207
+ }
4208
+ const pred = boundsToPred(term, acc);
4209
+ const bounded = abs({ k: "prim", type: "number" }, term, pred, "path");
4210
+ if (!mayNaN) return bounded;
4211
+ const nanArm = numLit(NaN);
4212
+ return makeSum(nanArm, bounded);
4213
+ }
4214
+ function roundingAbs(name, arg) {
4215
+ const phi2 = currentExecPhi();
4216
+ const impl = name === "round" ? Math.round : name === "floor" ? Math.floor : name === "ceil" ? Math.ceil : Math.trunc;
4217
+ const b = numericBounds(arg, phi2);
4218
+ const mayNaN = !isNonNaN(arg, phi2);
4219
+ const term = arg.term ? simplifyTerm(app(`Math.${name}`, [arg.term])) : void 0;
4220
+ let out = {};
4221
+ if (b) {
4222
+ if (b.lo !== void 0) {
4223
+ const v2 = impl(b.lo.value);
4224
+ out.lo = Number.isNaN(v2) ? void 0 : { value: v2, strict: false };
4225
+ }
4226
+ if (b.hi !== void 0) {
4227
+ const v2 = impl(b.hi.value);
4228
+ out.hi = Number.isNaN(v2) ? void 0 : { value: v2, strict: false };
4229
+ }
4230
+ }
4231
+ const pred = term ? boundsToPred(term, out) : void 0;
4232
+ const bounded = abs({ k: "prim", type: "number" }, term, pred, "path");
4233
+ if (!mayNaN) return bounded;
4234
+ return makeSum(numLit(NaN), bounded);
3777
4235
  }
3778
4236
  function evalMathMethod(name, args) {
3779
4237
  if (name === "random") return numPrim("path");
4238
+ if (name === "min" || name === "max") {
4239
+ const nums2 = [];
4240
+ let allLit = true;
4241
+ for (const a of args) {
4242
+ const n = coerceMathArg(a);
4243
+ if (n === void 0) {
4244
+ allLit = false;
4245
+ break;
4246
+ }
4247
+ if (n === "throw") throw new NudoThrow(errorTypeAbs("TypeError"));
4248
+ nums2.push(n);
4249
+ }
4250
+ if (allLit) {
4251
+ try {
4252
+ return numLit((name === "min" ? Math.min : Math.max)(...nums2));
4253
+ } catch {
4254
+ return numPrim();
4255
+ }
4256
+ }
4257
+ for (const a of args) {
4258
+ const n = coerceMathArg(a);
4259
+ if (n === "throw") throw new NudoThrow(errorTypeAbs("TypeError"));
4260
+ }
4261
+ return minMaxAbs(name, args);
4262
+ }
4263
+ if (name === "round" || name === "floor" || name === "ceil" || name === "trunc") {
4264
+ const n = coerceMathArg(args[0]);
4265
+ if (n === "throw") throw new NudoThrow(errorTypeAbs("TypeError"));
4266
+ if (typeof n === "number") {
4267
+ try {
4268
+ return numLit(
4269
+ name === "round" ? Math.round(n) : name === "floor" ? Math.floor(n) : name === "ceil" ? Math.ceil(n) : Math.trunc(n)
4270
+ );
4271
+ } catch {
4272
+ return numPrim();
4273
+ }
4274
+ }
4275
+ if (args[0]) {
4276
+ const c2 = coerceMathArg(args[0]);
4277
+ if (c2 === "throw") throw new NudoThrow(errorTypeAbs("TypeError"));
4278
+ return roundingAbs(name, args[0]);
4279
+ }
4280
+ return numPrim();
4281
+ }
3780
4282
  const impl = mathMethod(name);
3781
4283
  if (!impl) return void 0;
3782
4284
  const nums = [];
@@ -3952,16 +4454,6 @@ function isObjectProtoBrand(a) {
3952
4454
  return !!a && a.shape.k === "brand" && a.shape.name === "Object.prototype";
3953
4455
  }
3954
4456
 
3955
- // src/algebra/containers.ts
3956
- var TUPLE_LITERAL_CAP = 8;
3957
- function shouldWidenArrayLiteral(n) {
3958
- return n > TUPLE_LITERAL_CAP;
3959
- }
3960
- var TUPLE_MATERIALIZE_CAP = 4096;
3961
- function widenedArrayConf() {
3962
- return "path";
3963
- }
3964
-
3965
4457
  // src/algebra/builtins/object.ts
3966
4458
  function assignSourceSlots(src) {
3967
4459
  const s = src.shape;
@@ -4546,8 +5038,19 @@ function evalNumberStatic(name, args) {
4546
5038
  switch (name) {
4547
5039
  case "isInteger":
4548
5040
  return foldStrictNumberPred(Number.isInteger) ?? boolPrim();
4549
- case "isNaN":
4550
- return foldStrictNumberPred(Number.isNaN) ?? boolPrim();
5041
+ case "isNaN": {
5042
+ const folded = foldStrictNumberPred(Number.isNaN);
5043
+ if (folded) return folded;
5044
+ if (a0Arg?.term) {
5045
+ return abs(
5046
+ { k: "prim", type: "boolean" },
5047
+ void 0,
5048
+ { op: "eq", a: a0Arg.term, b: { op: "lit", value: NaN } },
5049
+ "path"
5050
+ );
5051
+ }
5052
+ return boolPrim();
5053
+ }
4551
5054
  case "isFinite":
4552
5055
  return foldStrictNumberPred(Number.isFinite) ?? boolPrim();
4553
5056
  case "parseInt": {
@@ -5403,7 +5906,7 @@ function arrayJoinToString(recv) {
5403
5906
  }
5404
5907
  function arrayMethodAbs(name) {
5405
5908
  return absFunction(["thisArg"], {
5406
- body: noBody,
5909
+ body: noBody2,
5407
5910
  bindThis: true,
5408
5911
  apply: (a) => {
5409
5912
  const recv = a[0] ?? undefAbs();
@@ -5766,11 +6269,11 @@ function evalPromiseCtor(args) {
5766
6269
  return undefAbs();
5767
6270
  };
5768
6271
  const resolveAbs = absFunction(["value"], {
5769
- body: noBody,
6272
+ body: noBody2,
5770
6273
  apply: (args2) => onResolve(args2[0])
5771
6274
  });
5772
6275
  const rejectAbs = absFunction(["reason"], {
5773
- body: noBody,
6276
+ body: noBody2,
5774
6277
  apply: (args2) => onReject(args2[0])
5775
6278
  });
5776
6279
  enterPromiseExecutorScope();
@@ -6453,7 +6956,7 @@ function evalObjectProtoMethod(name, thisVal, args) {
6453
6956
  }
6454
6957
  function objectProtoMethodAbs(name) {
6455
6958
  return absFunction(["thisArg", "arg0"], {
6456
- body: noBody,
6959
+ body: noBody2,
6457
6960
  bindThis: true,
6458
6961
  apply: (a) => {
6459
6962
  const recv = a[0] ?? undefLit();
@@ -11428,349 +11931,49 @@ ${inner}
11428
11931
  if (fn.async) {
11429
11932
  return `$fnVal(${nameList}, (${argsParamParts.join(", ")}) => $async(() => ${bodySrc}))`;
11430
11933
  }
11431
- return `$fnVal(${nameList}, (${argsParamParts.join(", ")}) => ${bodySrc})`;
11432
- }
11433
- case "MetaProperty":
11434
- return "$importMeta()";
11435
- case "ImportExpression": {
11436
- const specSrc = transpileExpression(expr.source, opts);
11437
- return `$dynamicImport(${specSrc})`;
11438
- }
11439
- case "JSXElement":
11440
- case "JSXFragment":
11441
- return "$unknown()";
11442
- default:
11443
- throw new NudoUnsupportedError(
11444
- `expression:${expr.type}`,
11445
- expr.loc ? { line: expr.loc.start.line, column: expr.loc.start.column } : void 0
11446
- );
11447
- }
11448
- }
11449
- bindTranspileExpression(transpileExpression);
11450
- bindTranspileShortCircuit(transpileShortCircuitExpr);
11451
-
11452
- // src/algebra/exec/transpile.ts
11453
- function transpileSource(source, opts = {}) {
11454
- const file = parseSource(source);
11455
- return transpileFile(file, { ...opts, source: opts.source ?? source });
11456
- }
11457
- function runtimeImportOf(runtime) {
11458
- return `import { $add, $sub, $mul, $div, $mod, $bitand, $bitor, $bitxor, $bitnot, $shl, $shr, $ushr, $pow, $toNumber, $toNumeric, $updateAdd, $updateSub, $in, $instanceof, $instanceofNonIdent, $classExpr, $del, $delRes, $objAccessor, $neg, $typeof, $not, $eq, $ne, $eqLoose, $neLoose, $lt, $le, $gt, $ge, $join, $lit, $fork, $for, $forIter, $obj, $get, $set, $setProto, $while, $whileSeq, $arr, $arrWithHoles, $arrMutContainer, $idx, $idxSet, $len, $call, $throw, $loopReturn, $loopBreak, $loopContinue, $class, $new, $invoke, $invokeSuper, $super, $async, $copy, $await, $asyncReturn, $orDefault, $callNamed, $optionalGet, $optionalInvoke, $spread, $concat, $forOf, $forInKeys, $catchVal, $switch, $staticInvoke, $setKey, $gen, $yield, $fnVal, $regex, $reStateCall, $rethrowIfNudoReturn, $nullishTest, $tryMark, $assignRecord, $recordBinding, $unknown, $importMeta, $dynamicImport, $tryTakeSince, $tryCurrentMark, $tryPopMark, $tryDigestSoftCatch, $tryReleaseSoftOut, $tryDetachSoftCatch, $tryDiscardSoft, $tryOrphanSoft, $pushLoopExit, $objRest, $arrRest, $elems, $arguments, $isForkExit, $rawThis, $isBreakTo } from ${JSON.stringify(runtime)};`;
11459
- }
11460
- function transpileFile(file, opts = {}) {
11461
- const runtime = opts.runtimeImport ?? "@nudojs/core/exec";
11462
- const lines = [
11463
- `// nudo evaluator transpile \u2014 values are Abs; operators are overloaded calls`,
11464
- `import { $add, $sub, $mul, $div, $mod, $bitand, $bitor, $bitxor, $bitnot, $shl, $shr, $ushr, $pow, $toNumber, $toNumeric, $updateAdd, $updateSub, $in, $instanceof, $instanceofNonIdent, $classExpr, $del, $delRes, $objAccessor, $neg, $typeof, $not, $eq, $ne, $eqLoose, $neLoose, $lt, $le, $gt, $ge, $join, $lit, $fork, $for, $forIter, $obj, $get, $set, $setProto, $while, $whileSeq, $arr, $arrWithHoles, $arrMutContainer, $idx, $idxSet, $len, $call, $throw, $loopReturn, $loopBreak, $loopContinue, $class, $new, $invoke, $invokeSuper, $super, $async, $copy, $await, $asyncReturn, $orDefault, $callNamed, $optionalGet, $optionalInvoke, $spread, $concat, $forOf, $forInKeys, $catchVal, $switch, $staticInvoke, $setKey, $gen, $yield, $fnVal, $regex, $reStateCall, $rethrowIfNudoReturn, $nullishTest, $tryMark, $assignRecord, $recordBinding, $unknown, $importMeta, $dynamicImport, $tryTakeSince, $tryCurrentMark, $tryPopMark, $tryDigestSoftCatch, $tryReleaseSoftOut, $tryDetachSoftCatch, $tryDiscardSoft, $tryOrphanSoft, $pushLoopExit, $objRest, $arrRest, $elems, $arguments, $isForkExit, $rawThis, $isBreakTo } from ${JSON.stringify(runtime)};`,
11465
- ``
11466
- ];
11467
- for (const stmt of file.program.body) {
11468
- lines.push(transpileStatement(stmt, 0, opts));
11469
- }
11470
- return lines.join("\n") + "\n";
11471
- }
11472
- function transpile(source, opts) {
11473
- return transpileSource(source, opts);
11474
- }
11475
-
11476
- // src/algebra/exec/runtime/state.ts
11477
- import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
11478
- function writeInPlace(target, next) {
11479
- target.shape = next.shape;
11480
- target.conf = next.conf;
11481
- target.term = void 0;
11482
- target.pred = void 0;
11483
- return target;
11484
- }
11485
- function clearStaleTermPred(v2) {
11486
- v2.term = void 0;
11487
- v2.pred = void 0;
11488
- }
11489
- var phi = pTrue;
11490
- function currentExecPhi() {
11491
- return phi;
11492
- }
11493
- function withExecPhi(p, body) {
11494
- const prev = phi;
11495
- phi = p;
11496
- try {
11497
- return body();
11498
- } finally {
11499
- phi = prev;
11500
- }
11501
- }
11502
- var noBody2 = { type: "BlockStatement", body: [], directives: [] };
11503
- function asAbsVal(v2) {
11504
- if (v2 && typeof v2 === "object" && "shape" in v2) return v2;
11505
- if (typeof v2 === "function") {
11506
- const n = Math.max(0, v2.length);
11507
- const params = Array.from({ length: n }, (_, i) => `arg${i}`);
11508
- return absFunction(params, {
11509
- body: noBody2,
11510
- // 与 $fnVal / $callNamed 同边界:callee 的 NudoReturn 不得冒泡成 caller
11511
- apply: (args) => callAtFunctionBoundary(() => v2(...args))
11512
- });
11513
- }
11514
- return $lit(v2);
11515
- }
11516
- function callAtFunctionBoundary(body) {
11517
- let forwarded = [];
11518
- try {
11519
- return runWithLoopExits(() => {
11520
- try {
11521
- const r = body();
11522
- forwarded = takeThrowExits();
11523
- return r;
11524
- } catch (e) {
11525
- forwarded = takeThrowExits();
11526
- if (isNudoReturn(e)) return e.absValue;
11527
- throw e;
11528
- }
11529
- });
11530
- } finally {
11531
- for (const x of forwarded) pushThrowExit(x);
11532
- }
11533
- }
11534
- function $fnVal(params, impl, opts) {
11535
- return absFunction(params, {
11536
- body: noBody2,
11537
- // bindThis(对象方法):receiver 走首参注入,无宿主 this;
11538
- // 非方法 fn:宿主 this 传递(call/apply/bind 的 thisArg 经 $rawThis 进入函数体)
11539
- apply: opts?.bindThis ? (args) => callAtFunctionBoundary(() => impl(...args)) : (args, thisVal) => callAtFunctionBoundary(() => impl.apply(thisVal, args)),
11540
- ...opts?.bindThis ? { bindThis: true } : {}
11541
- });
11542
- }
11543
- function $rawThis(v2) {
11544
- if (v2 === void 0 || v2 === globalThis) return $lit(void 0);
11545
- if (v2 && typeof v2 === "object" && "shape" in v2) return v2;
11546
- return $lit(v2);
11547
- }
11548
- function throwStrictWrite() {
11549
- throw new NudoThrow(errorTypeAbs("TypeError"));
11550
- }
11551
- function $throwConstAssign() {
11552
- throw new NudoThrow(errorTypeAbs("TypeError"));
11553
- }
11554
- function $litTruth(a) {
11555
- return litTruth(a);
11556
- }
11557
- function $lit(v2) {
11558
- if (v2 && typeof v2 === "object" && "shape" in v2 && "conf" in v2) {
11559
- return v2;
11560
- }
11561
- return litAbsFromJs(v2);
11562
- }
11563
- function litAbsFromJs(v2, depth = 0) {
11564
- if (v2 === null || v2 === void 0) {
11565
- return abs({ k: "unknown" }, { op: "lit", value: v2 }, pTrue, "exact");
11566
- }
11567
- const t = typeof v2;
11568
- if (t === "number" || t === "string" || t === "boolean" || t === "bigint") {
11569
- return abs(
11570
- { k: "prim", type: t },
11571
- { op: "lit", value: v2 },
11572
- pTrue,
11573
- "exact"
11574
- );
11575
- }
11576
- if (depth < 8) {
11577
- if (Array.isArray(v2)) {
11578
- const els = v2.map((x) => litAbsFromJs(x, depth + 1));
11579
- if (shouldWidenArrayLiteral(els.length)) {
11580
- return abs(
11581
- { k: "arr", element: els.reduce((x, y) => joinAbs(x, y)) },
11582
- void 0,
11583
- void 0,
11584
- widenedArrayConf()
11585
- );
11586
- }
11587
- return abs({ k: "tuple", elements: els }, void 0, void 0, "exact");
11588
- }
11589
- if (t === "object") {
11590
- const proto = Object.getPrototypeOf(v2);
11591
- if (proto === Object.prototype || proto === null) {
11592
- const slots = {};
11593
- for (const [k, val] of Object.entries(v2)) {
11594
- Object.defineProperty(slots, k, {
11595
- value: { value: litAbsFromJs(val, depth + 1) },
11596
- enumerable: true,
11597
- writable: true,
11598
- configurable: true
11599
- });
11600
- }
11601
- return objOf(slots);
11602
- }
11603
- }
11604
- }
11605
- return unknown;
11606
- }
11607
- function litTruth(a) {
11608
- if (a.term?.op === "lit") {
11609
- return Boolean(a.term.value);
11610
- }
11611
- switch (a.shape.k) {
11612
- case "obj":
11613
- case "arr":
11614
- case "tuple":
11615
- case "fn":
11616
- case "brand":
11617
- case "eff":
11618
- return true;
11619
- case "prim":
11620
- return a.shape.type === "symbol" ? true : void 0;
11621
- case "never":
11622
- return false;
11934
+ return `$fnVal(${nameList}, (${argsParamParts.join(", ")}) => ${bodySrc})`;
11935
+ }
11936
+ case "MetaProperty":
11937
+ return "$importMeta()";
11938
+ case "ImportExpression": {
11939
+ const specSrc = transpileExpression(expr.source, opts);
11940
+ return `$dynamicImport(${specSrc})`;
11941
+ }
11942
+ case "JSXElement":
11943
+ case "JSXFragment":
11944
+ return "$unknown()";
11623
11945
  default:
11624
- return void 0;
11625
- }
11626
- }
11627
- function isDefinitelyTrue(a) {
11628
- return litTruth(a) === true;
11629
- }
11630
- function isDefinitelyFalse(a) {
11631
- const t = litTruth(a);
11632
- if (t === false) return true;
11633
- if (a.shape.k === "never") return true;
11634
- return false;
11635
- }
11636
- function undef() {
11637
- return abs({ k: "unknown" }, { op: "lit", value: void 0 }, pTrue, "exact");
11638
- }
11639
- var loopExitsAls = new AsyncLocalStorage2();
11640
- var throwExitsAls = new AsyncLocalStorage2();
11641
- var tryMarksAls = new AsyncLocalStorage2();
11642
- var softFrameActiveAls = new AsyncLocalStorage2();
11643
- function runWithLoopExits(body) {
11644
- return loopExitsAls.run(
11645
- [],
11646
- () => throwExitsAls.run(
11647
- [],
11648
- () => tryMarksAls.run([], () => softFrameActiveAls.run([], body))
11649
- )
11650
- );
11651
- }
11652
- function takeLoopExits() {
11653
- return loopExitsAls.getStore() ?? [];
11654
- }
11655
- function takeThrowExits() {
11656
- return throwExitsAls.getStore() ?? [];
11657
- }
11658
- function pushLoopExit(v2) {
11659
- loopExitsAls.getStore()?.push(v2);
11660
- }
11661
- function pushThrowExit(v2) {
11662
- throwExitsAls.getStore()?.push(v2);
11663
- }
11664
- function $pushLoopExit(v2) {
11665
- pushLoopExit(v2);
11666
- }
11667
- function $tryMark() {
11668
- $tryMarkSoft();
11669
- softFrameActiveAls.getStore()?.push(true);
11670
- const store = throwExitsAls.getStore();
11671
- const m = store?.length ?? 0;
11672
- tryMarksAls.getStore()?.push(m);
11673
- return m;
11674
- }
11675
- function $tryCurrentMark() {
11676
- const stack = tryMarksAls.getStore();
11677
- return stack && stack.length > 0 ? stack[stack.length - 1] : 0;
11678
- }
11679
- function $tryPopMark() {
11680
- tryMarksAls.getStore()?.pop();
11681
- const soft = softFrameActiveAls.getStore();
11682
- if (soft && soft.length > 0) {
11683
- if (soft[soft.length - 1]) $tryReleaseSoftOut();
11684
- soft.pop();
11946
+ throw new NudoUnsupportedError(
11947
+ `expression:${expr.type}`,
11948
+ expr.loc ? { line: expr.loc.start.line, column: expr.loc.start.column } : void 0
11949
+ );
11685
11950
  }
11686
11951
  }
11687
- function $tryTakeSince(mark) {
11688
- const store = throwExitsAls.getStore();
11689
- if (!store) return [];
11690
- return store.splice(Math.min(mark, store.length));
11691
- }
11692
- function peekThrowExitsSince(mark) {
11693
- const store = throwExitsAls.getStore();
11694
- if (!store) return [];
11695
- return store.slice(Math.min(mark, store.length));
11696
- }
11697
- function throwExitsMark() {
11698
- return throwExitsAls.getStore()?.length ?? 0;
11699
- }
11700
- function $tryDigestSoftCatch() {
11701
- const soft = softFrameActiveAls.getStore();
11702
- if (!soft || soft.length === 0 || !soft[soft.length - 1]) return;
11703
- $tryDigestSoft();
11704
- soft[soft.length - 1] = false;
11705
- }
11706
- function $tryReleaseSoftCatch() {
11707
- const soft = softFrameActiveAls.getStore();
11708
- if (!soft || soft.length === 0 || !soft[soft.length - 1]) return;
11709
- $tryReleaseSoft();
11710
- soft[soft.length - 1] = false;
11711
- }
11712
- function $tryDetachSoftCatch() {
11713
- const soft = softFrameActiveAls.getStore();
11714
- if (!soft || soft.length === 0 || !soft[soft.length - 1]) return [];
11715
- const effects = popMayThrowFrame(false);
11716
- soft[soft.length - 1] = false;
11717
- return effects;
11718
- }
11719
- function $tryDiscardSoft(_effects) {
11720
- }
11721
- function $tryOrphanSoft(effects) {
11722
- orphanMayThrowEffects(effects);
11723
- }
11724
- function $tryReleaseSoftOut() {
11725
- const soft = softFrameActiveAls.getStore();
11726
- if (!soft || soft.length === 0 || !soft[soft.length - 1]) return;
11727
- $tryReleaseSoft();
11728
- soft[soft.length - 1] = false;
11729
- }
11730
- var NudoReturn = class extends Error {
11731
- absValue;
11732
- constructor(absValue) {
11733
- super("nudo:return");
11734
- this.name = "NudoReturn";
11735
- this.absValue = absValue;
11736
- }
11737
- };
11738
- function isNudoReturn(e) {
11739
- return e instanceof NudoReturn;
11952
+ bindTranspileExpression(transpileExpression);
11953
+ bindTranspileShortCircuit(transpileShortCircuitExpr);
11954
+
11955
+ // src/algebra/exec/transpile.ts
11956
+ function transpileSource(source, opts = {}) {
11957
+ const file = parseSource(source);
11958
+ return transpileFile(file, { ...opts, source: opts.source ?? source });
11740
11959
  }
11741
- function $loopReturn(v2) {
11742
- throw new NudoReturn(v2);
11960
+ function runtimeImportOf(runtime) {
11961
+ return `import { $add, $sub, $mul, $div, $mod, $bitand, $bitor, $bitxor, $bitnot, $shl, $shr, $ushr, $pow, $toNumber, $toNumeric, $updateAdd, $updateSub, $in, $instanceof, $instanceofNonIdent, $classExpr, $del, $delRes, $objAccessor, $neg, $typeof, $not, $eq, $ne, $eqLoose, $neLoose, $lt, $le, $gt, $ge, $join, $lit, $fork, $for, $forIter, $obj, $get, $set, $setProto, $while, $whileSeq, $arr, $arrWithHoles, $arrMutContainer, $idx, $idxSet, $len, $call, $throw, $loopReturn, $loopBreak, $loopContinue, $class, $new, $invoke, $invokeSuper, $super, $async, $copy, $await, $asyncReturn, $orDefault, $callNamed, $optionalGet, $optionalInvoke, $spread, $concat, $forOf, $forInKeys, $catchVal, $switch, $staticInvoke, $setKey, $gen, $yield, $fnVal, $regex, $reStateCall, $rethrowIfNudoReturn, $nullishTest, $tryMark, $assignRecord, $recordBinding, $unknown, $importMeta, $dynamicImport, $tryTakeSince, $tryCurrentMark, $tryPopMark, $tryDigestSoftCatch, $tryReleaseSoftOut, $tryDetachSoftCatch, $tryDiscardSoft, $tryOrphanSoft, $pushLoopExit, $objRest, $arrRest, $elems, $arguments, $isForkExit, $rawThis, $isBreakTo } from ${JSON.stringify(runtime)};`;
11743
11962
  }
11744
- var NudoLoopSignal = class extends Error {
11745
- kind;
11746
- label;
11747
- constructor(kind, label) {
11748
- super("nudo:loop");
11749
- this.name = "NudoLoopSignal";
11750
- this.kind = kind;
11751
- this.label = label;
11963
+ function transpileFile(file, opts = {}) {
11964
+ const runtime = opts.runtimeImport ?? "@nudojs/core/exec";
11965
+ const lines = [
11966
+ `// nudo evaluator transpile \u2014 values are Abs; operators are overloaded calls`,
11967
+ `import { $add, $sub, $mul, $div, $mod, $bitand, $bitor, $bitxor, $bitnot, $shl, $shr, $ushr, $pow, $toNumber, $toNumeric, $updateAdd, $updateSub, $in, $instanceof, $instanceofNonIdent, $classExpr, $del, $delRes, $objAccessor, $neg, $typeof, $not, $eq, $ne, $eqLoose, $neLoose, $lt, $le, $gt, $ge, $join, $lit, $fork, $for, $forIter, $obj, $get, $set, $setProto, $while, $whileSeq, $arr, $arrWithHoles, $arrMutContainer, $idx, $idxSet, $len, $call, $throw, $loopReturn, $loopBreak, $loopContinue, $class, $new, $invoke, $invokeSuper, $super, $async, $copy, $await, $asyncReturn, $orDefault, $callNamed, $optionalGet, $optionalInvoke, $spread, $concat, $forOf, $forInKeys, $catchVal, $switch, $staticInvoke, $setKey, $gen, $yield, $fnVal, $regex, $reStateCall, $rethrowIfNudoReturn, $nullishTest, $tryMark, $assignRecord, $recordBinding, $unknown, $importMeta, $dynamicImport, $tryTakeSince, $tryCurrentMark, $tryPopMark, $tryDigestSoftCatch, $tryReleaseSoftOut, $tryDetachSoftCatch, $tryDiscardSoft, $tryOrphanSoft, $pushLoopExit, $objRest, $arrRest, $elems, $arguments, $isForkExit, $rawThis, $isBreakTo } from ${JSON.stringify(runtime)};`,
11968
+ ``
11969
+ ];
11970
+ for (const stmt of file.program.body) {
11971
+ lines.push(transpileStatement(stmt, 0, opts));
11752
11972
  }
11753
- };
11754
- function $loopBreak(label) {
11755
- throw new NudoLoopSignal("break", label || void 0);
11756
- }
11757
- function $loopContinue(label) {
11758
- throw new NudoLoopSignal("continue", label || void 0);
11759
- }
11760
- function loopSignalMatches(e, label) {
11761
- return e.label === void 0 || e.label === label;
11762
- }
11763
- function isNudoBreak(e, label) {
11764
- return e instanceof NudoLoopSignal && e.kind === "break" && loopSignalMatches(e, label);
11765
- }
11766
- function isNudoContinue(e, label) {
11767
- return e instanceof NudoLoopSignal && e.kind === "continue" && loopSignalMatches(e, label);
11768
- }
11769
- function $isBreakTo(e, label) {
11770
- return e instanceof NudoLoopSignal && e.kind === "break" && e.label === label;
11973
+ return lines.join("\n") + "\n";
11771
11974
  }
11772
- function $rethrowIfNudoReturn(e) {
11773
- if (isNudoReturn(e)) throw e;
11975
+ function transpile(source, opts) {
11976
+ return transpileSource(source, opts);
11774
11977
  }
11775
11978
 
11776
11979
  // src/algebra/exec/runtime/ops.ts
@@ -13052,7 +13255,7 @@ function $get(o, key, opts) {
13052
13255
  const raw = o[key];
13053
13256
  if (typeof raw === "function") {
13054
13257
  return absFunction([`${ns}.${key}`], {
13055
- body: noBody2,
13258
+ body: noBody,
13056
13259
  apply: (args) => evalNamespaceCall(ns, key, args) ?? unknown
13057
13260
  });
13058
13261
  }
@@ -13071,7 +13274,7 @@ function $get(o, key, opts) {
13071
13274
  }
13072
13275
  if (o.shape.k === "eff" && o.shape.eff === "promise" && (key === "then" || key === "catch" || key === "finally")) {
13073
13276
  return absFunction([key === "then" ? "onFulfilled" : key === "catch" ? "onRejected" : "onFinally"], {
13074
- body: noBody2
13277
+ body: noBody
13075
13278
  });
13076
13279
  }
13077
13280
  if (o.shape.k === "brand") {
@@ -13082,7 +13285,7 @@ function $get(o, key, opts) {
13082
13285
  const isClassVal = classNameOfValue(o) === o.shape.name;
13083
13286
  const builtinM = BUILTIN_BRAND_METHODS[o.shape.name];
13084
13287
  if (builtinM && !isClassVal && (key === "@@iterator" || builtinM.has(key))) {
13085
- return absFunction([], { body: noBody2 });
13288
+ return absFunction([], { body: noBody });
13086
13289
  }
13087
13290
  if (key === "size" && o.shape.name === "Map") return mapSizeAbs(o);
13088
13291
  if (key === "size" && o.shape.name === "Set") return setSizeAbs(o);
@@ -13098,14 +13301,14 @@ function $get(o, key, opts) {
13098
13301
  for (const n of evalClassChain(o.shape.name)) {
13099
13302
  const spec = getEvalClass(n);
13100
13303
  if (spec?.staticMethods?.[key]) {
13101
- return absFunction(spec.staticMethodParams?.[key] ?? [], { body: noBody2 });
13304
+ return absFunction(spec.staticMethodParams?.[key] ?? [], { body: noBody });
13102
13305
  }
13103
13306
  }
13104
13307
  if (key === "prototype") {
13105
13308
  return abs({ k: "obj", slots: {} }, void 0, void 0, "path");
13106
13309
  }
13107
13310
  if (key === "call" || key === "apply" || key === "bind") {
13108
- return absFunction([], { body: noBody2 });
13311
+ return absFunction([], { body: noBody });
13109
13312
  }
13110
13313
  } else {
13111
13314
  const acc = findClassAccessor(o.shape.name, key);
@@ -13114,7 +13317,7 @@ function $get(o, key, opts) {
13114
13317
  for (const n of evalClassChain(o.shape.name)) {
13115
13318
  const spec = getEvalClass(n);
13116
13319
  if (spec?.methods?.[key]) {
13117
- return absFunction(spec.methodParams?.[key] ?? [], { body: noBody2 });
13320
+ return absFunction(spec.methodParams?.[key] ?? [], { body: noBody });
13118
13321
  }
13119
13322
  }
13120
13323
  }
@@ -16535,7 +16738,7 @@ function $instanceofNonIdent(_left) {
16535
16738
  }
16536
16739
  function $classExpr() {
16537
16740
  return absFunction(["_rest"], {
16538
- body: noBody2,
16741
+ body: noBody,
16539
16742
  apply: () => unknown
16540
16743
  });
16541
16744
  }
@@ -16797,6 +17000,43 @@ export {
16797
17000
  getPropFlags,
16798
17001
  setPropFlags,
16799
17002
  migrateInvariants,
17003
+ clearStaleTermPred,
17004
+ currentExecPhi,
17005
+ withExecPhi,
17006
+ asAbsVal,
17007
+ callAtFunctionBoundary,
17008
+ $fnVal,
17009
+ $rawThis,
17010
+ $lit,
17011
+ litTruth,
17012
+ isDefinitelyTrue,
17013
+ isDefinitelyFalse,
17014
+ runWithLoopExits,
17015
+ takeLoopExits,
17016
+ takeThrowExits,
17017
+ pushLoopExit,
17018
+ pushThrowExit,
17019
+ $pushLoopExit,
17020
+ $tryMark,
17021
+ $tryCurrentMark,
17022
+ $tryPopMark,
17023
+ $tryTakeSince,
17024
+ $tryDigestSoftCatch,
17025
+ $tryReleaseSoftCatch,
17026
+ $tryDetachSoftCatch,
17027
+ $tryDiscardSoft,
17028
+ $tryOrphanSoft,
17029
+ $tryReleaseSoftOut,
17030
+ NudoReturn,
17031
+ isNudoReturn,
17032
+ $loopReturn,
17033
+ NudoLoopSignal,
17034
+ $loopBreak,
17035
+ $loopContinue,
17036
+ isNudoBreak,
17037
+ isNudoContinue,
17038
+ $isBreakTo,
17039
+ $rethrowIfNudoReturn,
16800
17040
  evalMathMethod,
16801
17041
  builtinCtorAbs,
16802
17042
  builtinCtorNameOf,
@@ -16965,43 +17205,6 @@ export {
16965
17205
  runtimeImportOf,
16966
17206
  transpileFile,
16967
17207
  transpile,
16968
- clearStaleTermPred,
16969
- currentExecPhi,
16970
- withExecPhi,
16971
- asAbsVal,
16972
- callAtFunctionBoundary,
16973
- $fnVal,
16974
- $rawThis,
16975
- $lit,
16976
- litTruth,
16977
- isDefinitelyTrue,
16978
- isDefinitelyFalse,
16979
- runWithLoopExits,
16980
- takeLoopExits,
16981
- takeThrowExits,
16982
- pushLoopExit,
16983
- pushThrowExit,
16984
- $pushLoopExit,
16985
- $tryMark,
16986
- $tryCurrentMark,
16987
- $tryPopMark,
16988
- $tryTakeSince,
16989
- $tryDigestSoftCatch,
16990
- $tryReleaseSoftCatch,
16991
- $tryDetachSoftCatch,
16992
- $tryDiscardSoft,
16993
- $tryOrphanSoft,
16994
- $tryReleaseSoftOut,
16995
- NudoReturn,
16996
- isNudoReturn,
16997
- $loopReturn,
16998
- NudoLoopSignal,
16999
- $loopBreak,
17000
- $loopContinue,
17001
- isNudoBreak,
17002
- isNudoContinue,
17003
- $isBreakTo,
17004
- $rethrowIfNudoReturn,
17005
17208
  $unknown,
17006
17209
  $importMeta,
17007
17210
  $dynamicImport,
@@ -45,7 +45,7 @@ import {
45
45
  withEvalBudgetOverride,
46
46
  withExecPhi,
47
47
  withFnBudgetOverride
48
- } from "./chunk-LFCF6BLE.js";
48
+ } from "./chunk-W2MP6REI.js";
49
49
 
50
50
  // src/algebra/directive-scan.ts
51
51
  function cleanDirectiveLine(raw, kind) {
package/dist/exec.js CHANGED
@@ -176,7 +176,7 @@ import {
176
176
  tryRunTranspiled,
177
177
  withEvalBudgetOverride,
178
178
  withExecPhi
179
- } from "./chunk-LFCF6BLE.js";
179
+ } from "./chunk-W2MP6REI.js";
180
180
  export {
181
181
  $add,
182
182
  $arguments,
package/dist/index.d.ts CHANGED
@@ -365,7 +365,12 @@ declare function setPropFlags(o: Abs, key: string, f: PropFlags): void;
365
365
  declare function migrateInvariants(from: Abs, to: Abs): void;
366
366
 
367
367
  /**
368
- * Math.* — 字面量实参走 ToNumber/ToInt32 后调用原生折叠,否则 number
368
+ * Math.* — 字面量实参走 ToNumber/ToInt32 后调用原生折叠;非字面量对
369
+ * min/max/round/floor/ceil/trunc 透传数值区间(#68)。
370
+ *
371
+ * NaN 策略(DEC:显式 NaN 臂):操作数可能为 NaN 时结果为
372
+ * `NaN | number@bounds`。契约 `ge(0).le(100)` 对 NaN 臂诚实报违例;
373
+ * `if (Number.isNaN(n)) return …` 假臂的 `ne(n, NaN)` 事实可排除 NaN 臂。
369
374
  */
370
375
 
371
376
  declare function evalMathMethod(name: string, args: Abs[]): Abs | undefined;
package/dist/index.js CHANGED
@@ -91,7 +91,7 @@ import {
91
91
  takeRefineDiagsSince,
92
92
  throwConstraintToKinds,
93
93
  union
94
- } from "./chunk-7QUVTEYZ.js";
94
+ } from "./chunk-YO4GKCNE.js";
95
95
  import {
96
96
  $add,
97
97
  $arguments,
@@ -507,7 +507,7 @@ import {
507
507
  v,
508
508
  withExecPhi,
509
509
  withVar
510
- } from "./chunk-LFCF6BLE.js";
510
+ } from "./chunk-W2MP6REI.js";
511
511
 
512
512
  // src/environment.ts
513
513
  function createEnvironment(parent, bindings = /* @__PURE__ */ new Map()) {
@@ -768,60 +768,92 @@ function isBoundedEvidenceMissing(ret, constraint) {
768
768
  if (ret.pred && ret.pred.op !== "true") return false;
769
769
  return true;
770
770
  }
771
+ function flattenSumArms(ret) {
772
+ if (ret.shape.k !== "sum") return [ret];
773
+ const out = [];
774
+ for (const m of ret.shape.members) {
775
+ if (m.shape.k === "sum") out.push(...flattenSumArms(m));
776
+ else out.push(m);
777
+ }
778
+ return out;
779
+ }
780
+ function isWidenedSumArm(m, parent) {
781
+ return parent.conf === "partial" && m.shape.k === "prim" && !m.term && (!m.pred || m.pred.op === "true");
782
+ }
771
783
  function assertImplies(ret, constraint, opts) {
772
784
  const phi = opts?.phi ?? pTrue;
773
785
  if (ret.shape.k === "never") return proved();
774
786
  if (isAnyConstraint(constraint)) return proved();
775
- const nullishOk = constraintAdmitsNullish(constraint);
776
- if (isNullishLitAbs(ret)) {
777
- return nullishOk ? proved() : disproved(`nullish return \u22AD ${formatConstraint(constraint)}`);
778
- }
779
- let sumMembers;
780
- if (ret.shape.k === "sum") {
781
- const members = ret.shape.members;
782
- const nullishMembers = members.filter((m) => isNullishLitAbs(m));
783
- if (nullishMembers.length > 0 && !nullishOk) {
784
- return disproved(
785
- `nullish return arm \u22AD ${formatConstraint(constraint)} (contract does not admit nullish)`
786
- );
787
- }
788
- sumMembers = members.filter((m) => !isNullishLitAbs(m));
789
- }
790
787
  if (isValueSetUnknown(ret)) {
791
788
  return unprovable(
792
789
  ret.shape.k === "any" ? "any does not establish the return contract" : "inference failure (unknown/opaque) \u2014 cannot prove the return contract"
793
790
  );
794
791
  }
792
+ const arms = flattenSumArms(ret);
793
+ if (arms.length > 1) {
794
+ return assertSumArms(arms, ret, constraint, opts, phi);
795
+ }
796
+ return assertImpliesSingle(arms[0], constraint, opts, phi);
797
+ }
798
+ function assertSumArms(arms, parent, constraint, opts, phi) {
799
+ const hasWidenedArm = arms.some(
800
+ (a) => isValueSetUnknown(a) || isWidenedSumArm(a, parent)
801
+ );
802
+ let sawUnprovable = false;
803
+ for (const arm of arms) {
804
+ if (isNullishLitAbs(arm)) {
805
+ if (!constraintAdmitsNullish(constraint)) {
806
+ return disproved(
807
+ `nullish return arm \u22AD ${formatConstraint(constraint)} (contract does not admit nullish)`
808
+ );
809
+ }
810
+ continue;
811
+ }
812
+ if (isValueSetUnknown(arm) || isWidenedSumArm(arm, parent)) {
813
+ sawUnprovable = true;
814
+ continue;
815
+ }
816
+ const r = assertImpliesSingle(arm, constraint, opts, phi);
817
+ if (r.status === "disproved") {
818
+ if (hasWidenedArm) {
819
+ sawUnprovable = true;
820
+ continue;
821
+ }
822
+ return r;
823
+ }
824
+ if (r.status === "unprovable") sawUnprovable = true;
825
+ }
826
+ return sawUnprovable ? unprovable("sum: some arms unprovable") : proved();
827
+ }
828
+ function assertImpliesSingle(arm, constraint, opts, phi) {
829
+ if (isNullishLitAbs(arm)) {
830
+ return constraintAdmitsNullish(constraint) ? proved() : disproved(`nullish return \u22AD ${formatConstraint(constraint)}`);
831
+ }
832
+ if (isValueSetUnknown(arm)) {
833
+ return unprovable(
834
+ arm.shape.k === "any" ? "any does not establish the return contract" : "inference failure (unknown/opaque) \u2014 cannot prove the return contract"
835
+ );
836
+ }
795
837
  if (constraint.members && constraint.members.length > 0) {
796
838
  let sawUnprovable = false;
797
839
  for (const m of constraint.members) {
798
- const r = assertImplies(ret, m, opts);
840
+ const r = assertImplies(arm, m, opts);
799
841
  if (r.status === "proved") return proved();
800
842
  if (r.status === "unprovable") sawUnprovable = true;
801
843
  }
802
844
  return sawUnprovable ? unprovable("union: no member proved the return contract") : disproved(`return \u22AD union(${constraint.members.map((m) => formatConstraint(m)).join(", ")})`);
803
845
  }
804
- if (sumMembers && (constraint.fields || constraint.element)) {
805
- let sawUnprovable = false;
806
- for (const m of sumMembers) {
807
- if (isValueSetUnknown(m)) continue;
808
- const r = assertImplies(m, constraint, opts);
809
- if (r.status === "disproved") return r;
810
- if (r.status === "unprovable") sawUnprovable = true;
811
- }
812
- return sawUnprovable ? unprovable("sum: some arms unprovable") : proved();
813
- }
814
846
  if (constraint.fields) {
815
- return assertShapeFields(ret, constraint, opts);
847
+ return assertShapeFields(arm, constraint, opts);
816
848
  }
817
849
  if (constraint.element) {
818
- if (ret.shape.k !== "arr" && ret.shape.k !== "tuple") {
819
- return disproved(`return shape ${ret.shape.k} \u22AD array(...)`);
850
+ if (arm.shape.k !== "arr" && arm.shape.k !== "tuple") {
851
+ return disproved(`return shape ${arm.shape.k} \u22AD array(...)`);
820
852
  }
821
853
  return proved();
822
854
  }
823
855
  if (constraint.fn) return proved();
824
- return assertScalar(ret, constraint, phi);
856
+ return assertScalar(arm, constraint, phi);
825
857
  }
826
858
  function isAnyConstraint(c) {
827
859
  return !c.prim && c.preds.length === 0 && !c.fields && !c.element && !c.members && !c.fn && !isIntFlag(c);
@@ -2214,7 +2246,7 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
2214
2246
  message: `${name} (export): may throw ${gateDisplay}`,
2215
2247
  actual: `${name}(\u2026) throws ${gateDisplay}`,
2216
2248
  expected: "entry total, or @nudo:throws / try-catch",
2217
- suggestion: first.cause ? `${first.cause} \u2192 ${first.kind === "ReferenceError" ? "re-export `export { x } from` \u4E0D\u662F\u5C40\u90E8\u7ED1\u5B9A\u2014\u2014\u6539 `import { x }` / @nudo:throws ReferenceError" : `@nudo:throws ${first.kind} / sidecar fn({ \u2026 }) contract / refine / guard / try-catch`}` : first.kind === "ReferenceError" ? "re-export `export { x } from` \u4E0D\u662F\u5C40\u90E8\u7ED1\u5B9A\u2014\u2014\u6539 `import { x }` / @nudo:throws ReferenceError" : `@nudo:throws ${first.kind} / sidecar fn({ \u2026 }) contract / refine / guard / try-catch`,
2249
+ suggestion: first.cause ? `${first.cause} \u2192 ${first.kind === "ReferenceError" ? "re-export `export { x } from` \u4E0D\u662F\u5C40\u90E8\u7ED1\u5B9A\u2014\u2014\u6539 `import { x }` / @nudo:throws ReferenceError" : `@nudo:throws ${first.kind} | sidecar: fn({ \u2026 }): shape({ <body-read fields> }) | refine / guard / try-catch`}` : first.kind === "ReferenceError" ? "re-export `export { x } from` \u4E0D\u662F\u5C40\u90E8\u7ED1\u5B9A\u2014\u2014\u6539 `import { x }` / @nudo:throws ReferenceError" : `@nudo:throws ${first.kind} | sidecar: fn({ \u2026 }): shape({ <body-read fields> }) | refine / guard / try-catch`,
2218
2250
  fn: name,
2219
2251
  ...loc.line !== void 0 ? { line: loc.line } : {},
2220
2252
  ...loc.column !== void 0 ? { column: loc.column } : {}
@@ -2259,7 +2291,7 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
2259
2291
  message: `${name} (export): may throw ${gateDisplay}`,
2260
2292
  actual: `${formatEntrySigLine(name, g, gateDisplay)}`,
2261
2293
  expected: "entry total, or @nudo:throws / try-catch",
2262
- suggestion: first.cause ? `${first.cause} \u2192 ${first.kind === "ReferenceError" ? "re-export `export { x } from` \u4E0D\u662F\u5C40\u90E8\u7ED1\u5B9A\u2014\u2014\u6539 `import { x }` / @nudo:throws ReferenceError" : `@nudo:throws ${first.kind} / sidecar fn({ \u2026 }) contract / refine / guard / try-catch`}` : first.kind === "ReferenceError" ? "re-export `export { x } from` \u4E0D\u662F\u5C40\u90E8\u7ED1\u5B9A\u2014\u2014\u6539 `import { x }` / @nudo:throws ReferenceError" : `@nudo:throws ${first.kind} / sidecar fn({ \u2026 }) contract / refine / guard / try-catch`,
2294
+ suggestion: first.cause ? `${first.cause} \u2192 ${first.kind === "ReferenceError" ? "re-export `export { x } from` \u4E0D\u662F\u5C40\u90E8\u7ED1\u5B9A\u2014\u2014\u6539 `import { x }` / @nudo:throws ReferenceError" : `@nudo:throws ${first.kind} | sidecar: fn({ \u2026 }): shape({ <body-read fields> }) | refine / guard / try-catch`}` : first.kind === "ReferenceError" ? "re-export `export { x } from` \u4E0D\u662F\u5C40\u90E8\u7ED1\u5B9A\u2014\u2014\u6539 `import { x }` / @nudo:throws ReferenceError" : `@nudo:throws ${first.kind} | sidecar: fn({ \u2026 }): shape({ <body-read fields> }) | refine / guard / try-catch`,
2263
2295
  fn: name,
2264
2296
  ...loc.line !== void 0 ? { line: loc.line } : {},
2265
2297
  ...loc.column !== void 0 ? { column: loc.column } : {}
@@ -2627,6 +2659,19 @@ function actionsForIssue(i) {
2627
2659
  label: "migration switch: ignore this throw class on L2"
2628
2660
  }
2629
2661
  ];
2662
+ case "nudo:unproven-return":
2663
+ return [
2664
+ {
2665
+ kind: "relax",
2666
+ label: `relax the return contract${i.fn ? ` of ${i.fn}` : ""} to the inferred surface (review the diff \u2014 not a silent green)`,
2667
+ ...i.expected ? { hint: i.expected } : {}
2668
+ },
2669
+ draft,
2670
+ {
2671
+ kind: "info",
2672
+ label: "or narrow the return expression / add a precondition so the bound is implied"
2673
+ }
2674
+ ];
2630
2675
  case "nudo:unknown-inference":
2631
2676
  case "nudo:opaque-result":
2632
2677
  return [
package/dist/internal.js CHANGED
@@ -18,7 +18,7 @@ import {
18
18
  stableAnalyzeKeySource,
19
19
  stablePathKey,
20
20
  stablePathKeyGraph
21
- } from "./chunk-7QUVTEYZ.js";
21
+ } from "./chunk-YO4GKCNE.js";
22
22
  import {
23
23
  $tryDigestSoft,
24
24
  $tryMarkSoft,
@@ -157,7 +157,7 @@ import {
157
157
  withEvalBudgetOverride,
158
158
  withFnBudgetOverride,
159
159
  wrapPromise
160
- } from "./chunk-LFCF6BLE.js";
160
+ } from "./chunk-W2MP6REI.js";
161
161
 
162
162
  // src/algebra/inlay.ts
163
163
  function listFunctions(source) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nudojs/core",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "engines": {
5
5
  "node": ">=20"
6
6
  },