@neocompose/cli 0.85.0 → 0.86.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.
@@ -1333,6 +1333,34 @@ function compareGroupIds(left, right) {
1333
1333
  return 0;
1334
1334
  }
1335
1335
 
1336
+ // ../packages/neoscript-language/src/bitwise.ts
1337
+ var ARITIES = {
1338
+ and: 2,
1339
+ or: 2,
1340
+ xor: 2,
1341
+ not: 1,
1342
+ shiftLeft: 2,
1343
+ shiftRight: 2,
1344
+ shiftRightUnsigned: 2
1345
+ };
1346
+ function isNeoScriptBitwiseOp(value) {
1347
+ return typeof value === "string" && Object.hasOwn(ARITIES, value);
1348
+ }
1349
+ function neoScriptBitwiseOpArity(op) {
1350
+ return ARITIES[op];
1351
+ }
1352
+ var BITWISE_BINARY_OPERATORS = {
1353
+ "&": "and",
1354
+ "|": "or",
1355
+ "^": "xor",
1356
+ "<<": "shiftLeft",
1357
+ ">>": "shiftRight",
1358
+ ">>>": "shiftRightUnsigned"
1359
+ };
1360
+ function isBitwiseBinaryOperator(value) {
1361
+ return Object.hasOwn(BITWISE_BINARY_OPERATORS, value);
1362
+ }
1363
+
1336
1364
  // ../packages/neoscript-language/src/dialogue-types.ts
1337
1365
  var NEOSCRIPT_DIALOGUES_MEMBER_NAME = "Dialogues";
1338
1366
  var NEOSCRIPT_DIALOGUES_TYPE_ID = "builtin:Dialogues";
@@ -1480,17 +1508,17 @@ var KIND_LABELS = {
1480
1508
  };
1481
1509
  function neoScriptDialogueTypes(groups) {
1482
1510
  const names = dialogueGroupPropertyNames(groups);
1483
- const children = /* @__PURE__ */ new Map();
1511
+ const children3 = /* @__PURE__ */ new Map();
1484
1512
  for (const group of groups) {
1485
- const siblings = children.get(group.parentId);
1486
- if (siblings === void 0) children.set(group.parentId, [group]);
1513
+ const siblings = children3.get(group.parentId);
1514
+ if (siblings === void 0) children3.set(group.parentId, [group]);
1487
1515
  else siblings.push(group);
1488
1516
  }
1489
1517
  const rootPath = `root.${NEOSCRIPT_DIALOGUES_MEMBER_NAME}`;
1490
1518
  const types = [];
1491
1519
  const typeFor = (parentId, path) => {
1492
1520
  const members2 = [];
1493
- for (const group of children.get(parentId) ?? []) {
1521
+ for (const group of children3.get(parentId) ?? []) {
1494
1522
  const name = names.get(group.id);
1495
1523
  const groupPath = `${path}.${name}`;
1496
1524
  const typeId = `${NEOSCRIPT_DIALOGUES_TYPE_ID}:${group.id}`;
@@ -1552,7 +1580,7 @@ function neoScriptDialogueTypes(groups) {
1552
1580
  }
1553
1581
 
1554
1582
  // ../packages/neoscript-language/src/vector-math.ts
1555
- var ARITIES = {
1583
+ var ARITIES2 = {
1556
1584
  add: 2,
1557
1585
  subtract: 2,
1558
1586
  negate: 1,
@@ -1574,10 +1602,10 @@ function isNeoScriptVectorKind(value) {
1574
1602
  return value === "Vector2" || value === "Vector2Int" || value === "Vector3" || value === "Vector3Int" || value === "Color";
1575
1603
  }
1576
1604
  function neoScriptVectorOpArity(op) {
1577
- return ARITIES[op];
1605
+ return ARITIES2[op];
1578
1606
  }
1579
1607
  function isNeoScriptVectorOpForKind(kind, op) {
1580
- if (typeof op !== "string" || !Object.hasOwn(ARITIES, op)) return false;
1608
+ if (typeof op !== "string" || !Object.hasOwn(ARITIES2, op)) return false;
1581
1609
  if (kind === "Color") return op === "lerp";
1582
1610
  if (op === "cross") return kind === "Vector3";
1583
1611
  if (kind.endsWith("Int")) {
@@ -1812,6 +1840,19 @@ function isNeoVariantTypeName(name) {
1812
1840
  return name === NEO_VARIANT_TYPE_NAME || name === NEO_LOOKUP_VARIANT_TYPE_NAME;
1813
1841
  }
1814
1842
  var NEOSCRIPT_OPERATORS = [
1843
+ ">>>=",
1844
+ ">>=",
1845
+ "<<=",
1846
+ ">>>",
1847
+ ">>",
1848
+ "<<",
1849
+ "&=",
1850
+ "|=",
1851
+ "^=",
1852
+ "&",
1853
+ "|",
1854
+ "^",
1855
+ "~",
1815
1856
  "===",
1816
1857
  "!==",
1817
1858
  "==",
@@ -3455,7 +3496,7 @@ function isNSPointerMemberTarget(value) {
3455
3496
  return isNSCallReceiver(pointer.receiver);
3456
3497
  }
3457
3498
  function isNSPointer(value) {
3458
- return isNSPointerReference(value) || isNSPointerVariable(value) || isNSPointerStaticMember(value) || isNSPointerValue(value) || isNSPointerOperation(value) || isNSPointerFunction(value) || isNSPointerKeyOf(value) || isNSPointerListLiteral(value) || isNSPointerDictLiteral(value) || isNSPointerForceUnwrap(value) || isNSPointerRowOf(value) || isNSPointerDeref(value) || isNSPointerIsCheck(value) || isNSPointerCallGetter(value) || isNSPointerCoalesce(value) || isNSPointerConditional(value) || isNSPointerMemberTarget(value) || isNSPointerDelegateClosure(value) || isNSPointerObjectInitializer(value) || isNSPointerToBool(value) || isNSPointerStringify(value) || isNSPointerTileConvert(value) || isNSPointerCallFunction(value) || isNSPointerCallDelegate(value) || isNSPointerCallAction(value) || isNSPointerVariant(value) || isNSPointerFunctionErrorCheck(value);
3499
+ return isNSPointerReference(value) || isNSPointerVariable(value) || isNSPointerStaticMember(value) || isNSPointerValue(value) || isNSPointerOperation(value) || isNSPointerFunction(value) || isNSPointerKeyOf(value) || isNSPointerListLiteral(value) || isNSPointerDictLiteral(value) || isNSPointerForceUnwrap(value) || isNSPointerRowOf(value) || isNSPointerDeref(value) || isNSPointerIsCheck(value) || isNSPointerCallGetter(value) || isNSPointerCoalesce(value) || isNSPointerConditional(value) || isNSPointerSwitchExpression(value) || isNSPointerMemberTarget(value) || isNSPointerDelegateClosure(value) || isNSPointerObjectInitializer(value) || isNSPointerToBool(value) || isNSPointerStringify(value) || isNSPointerTileConvert(value) || isNSPointerCallFunction(value) || isNSPointerCallDelegate(value) || isNSPointerCallAction(value) || isNSPointerVariant(value) || isNSPointerFunctionErrorCheck(value);
3459
3500
  }
3460
3501
  function isNSPointers(value) {
3461
3502
  return Array.isArray(value) && value.every(isNSPointer);
@@ -3784,6 +3825,20 @@ function isNSFunctionTextOp(value) {
3784
3825
  if (!NS_TEXT_NUMBER_OPS.includes(info.op)) return false;
3785
3826
  return NS_TEXT_NUMBERS.includes(info.number);
3786
3827
  }
3828
+ function isNSFunctionBitwiseOp(value) {
3829
+ if (typeof value !== "object" || value === null) return false;
3830
+ if (!("type" in value) || value.type !== "bitwiseOp" /* bitwiseOp */)
3831
+ return false;
3832
+ if (!("info" in value) || typeof value.info !== "object" || value.info === null)
3833
+ return false;
3834
+ const info = value.info;
3835
+ if (!("op" in info) || !isNeoScriptBitwiseOp(info.op)) return false;
3836
+ if (!("argPointers" in info) || !Array.isArray(info.argPointers))
3837
+ return false;
3838
+ if (info.argPointers.length !== neoScriptBitwiseOpArity(info.op))
3839
+ return false;
3840
+ return info.argPointers.every(isNSPointer);
3841
+ }
3787
3842
  function isNSFunctionVectorOp(value) {
3788
3843
  if (typeof value !== "object" || value === null) return false;
3789
3844
  if (!("type" in value) || value.type !== "vectorOp" /* vectorOp */)
@@ -3941,7 +3996,7 @@ function isNSFunction(value) {
3941
3996
  return isNSFunctionClassConstructor(value) || isNSFunctionClassClone(value) || isNSFunctionListIndex(value) || isNSFunctionSelect(value) || isNSFunctionCollectionQuery(value) || isNSFunctionFirst(value) || isNSFunctionFirstOrDefault(value) || isNSFunctionWhere(value) || isNSFunctionContains(value) || isNSFunctionIndexOf(value) || // stringOp was missing from this chain since its introduction — a
3942
3997
  // compiled getter using ToLower()/StartsWith() would fail pointer
3943
3998
  // validation anywhere isNSFunction gates. Fixed alongside decimalOp.
3944
- isNSFunctionStringOp(value) || isNSFunctionDecimalOp(value) || isNSFunctionMathOp(value) || isNSFunctionVectorOp(value) || isNSFunctionListRepeat(value) || isNSFunctionTextOp(value) || isNSFunctionCount(value) || isNSFunctionVisitCount(value) || isNSFunctionHasVisited(value) || isNSFunctionDialogueGroup(value) || isNSFunctionDialogue(value) || isNSFunctionVectorConstructor(value) || isNSFunctionImageSlice(value) || isNSFunctionVariantInitialize(value) || isNSFunctionVariantApply(value) || isNSFunctionDeclaredConstructor(value);
3999
+ isNSFunctionStringOp(value) || isNSFunctionDecimalOp(value) || isNSFunctionMathOp(value) || isNSFunctionBitwiseOp(value) || isNSFunctionVectorOp(value) || isNSFunctionListRepeat(value) || isNSFunctionTextOp(value) || isNSFunctionCount(value) || isNSFunctionVisitCount(value) || isNSFunctionHasVisited(value) || isNSFunctionDialogueGroup(value) || isNSFunctionDialogue(value) || isNSFunctionVectorConstructor(value) || isNSFunctionImageSlice(value) || isNSFunctionVariantInitialize(value) || isNSFunctionVariantApply(value) || isNSFunctionDeclaredConstructor(value);
3945
4000
  }
3946
4001
  function isNSInstructionVariable(value) {
3947
4002
  const v = value;
@@ -4210,6 +4265,35 @@ function isNSVoidBody(value) {
4210
4265
  if (value.typeInfo.type !== 0 /* Null */) return false;
4211
4266
  return value.typeInfo.required === true;
4212
4267
  }
4268
+ function isNSPointerSwitchExpression(value) {
4269
+ if (typeof value !== "object" || value === null || !("type" in value) || value.type !== "switchExpression" /* switchExpression */)
4270
+ return false;
4271
+ if (!("selectorTypeInfo" in value) || !isNSTypeInfo(value.selectorTypeInfo))
4272
+ return false;
4273
+ if (!("selector" in value) || !isNSPointer(value.selector)) return false;
4274
+ if (!("selectorId" in value) || typeof value.selectorId !== "string" || value.selectorId.length === 0)
4275
+ return false;
4276
+ if (!("arms" in value) || !Array.isArray(value.arms) || value.arms.length === 0)
4277
+ return false;
4278
+ const selectorTypeInfo = value.selectorTypeInfo;
4279
+ return value.arms.every((arm) => {
4280
+ if (typeof arm !== "object" || arm === null) return false;
4281
+ if (!("value" in arm) || !isNSPointer(arm.value)) return false;
4282
+ if ("guard" in arm && !isNSPointer(arm.guard)) return false;
4283
+ if (!("pattern" in arm) || typeof arm.pattern !== "object" || arm.pattern === null)
4284
+ return false;
4285
+ const pattern = arm.pattern;
4286
+ if (!("kind" in pattern)) return false;
4287
+ if (pattern.kind === "discard") return true;
4288
+ if (pattern.kind === "constant")
4289
+ return "constant" in pattern && nsSwitchLabelKey(pattern.constant, selectorTypeInfo) !== null;
4290
+ if (pattern.kind !== "type") return false;
4291
+ if (!("checkType" in pattern) || !isNSTypeInfo(pattern.checkType))
4292
+ return false;
4293
+ if (pattern.checkType.required !== true) return false;
4294
+ return !("bindingId" in pattern) || typeof pattern.bindingId === "string" && pattern.bindingId.length > 0;
4295
+ });
4296
+ }
4213
4297
 
4214
4298
  // ../packages/models/src/neoscript/parameter-defaults.ts
4215
4299
  function parameterHasDefault(argument2) {
@@ -5447,9 +5531,9 @@ function isMemberChangeListenerEntry(value) {
5447
5531
  const identities = /* @__PURE__ */ new Set();
5448
5532
  for (const target of targets) {
5449
5533
  if (!isMemberDelegateTarget(target)) return false;
5450
- const identity = nsActionListenerIdentity(target);
5451
- if (identities.has(identity)) return false;
5452
- identities.add(identity);
5534
+ const identity2 = nsActionListenerIdentity(target);
5535
+ if (identities.has(identity2)) return false;
5536
+ identities.add(identity2);
5453
5537
  }
5454
5538
  }
5455
5539
  return true;
@@ -5550,9 +5634,9 @@ function isNSActionValue(value) {
5550
5634
  const identities = /* @__PURE__ */ new Set();
5551
5635
  for (const listener of record4.listeners) {
5552
5636
  if (!isMemberDelegateTarget(listener)) return false;
5553
- const identity = nsActionListenerIdentity(listener);
5554
- if (identities.has(identity)) return false;
5555
- identities.add(identity);
5637
+ const identity2 = nsActionListenerIdentity(listener);
5638
+ if (identities.has(identity2)) return false;
5639
+ identities.add(identity2);
5556
5640
  }
5557
5641
  return true;
5558
5642
  }
@@ -6599,7 +6683,10 @@ async function forEachConcurrently(items, limit, work) {
6599
6683
 
6600
6684
  // ../packages/models/src/classes/classes.ts
6601
6685
  function isAbstractClass(value) {
6602
- return value?.modifier === 1 /* Abstract */;
6686
+ return value?.modifier === 1 /* Abstract */ || value?.modifier === 3 /* Closed */;
6687
+ }
6688
+ function isClosedHierarchyClass(value) {
6689
+ return value?.modifier === 3 /* Closed */;
6603
6690
  }
6604
6691
  function isSealedClass(value) {
6605
6692
  return value?.modifier === 2 /* Sealed */;
@@ -6691,7 +6778,7 @@ function isNeoSchemaClassBase(value) {
6691
6778
  const v = value;
6692
6779
  return typeof v?.name === "string" && isValidDocsText(v.docsText) && isClassSchema(v?.schema) && isOptionalSchemaKeyOrder(v?.schemaKeyOrder) && (v.implementsInterfaceIds === void 0 || Array.isArray(v.implementsInterfaceIds) && v.implementsInterfaceIds.every(
6693
6780
  (interfaceId) => typeof interfaceId === "string" && interfaceId.length > 0
6694
- )) && (v.uiVisibility === void 0 || v.uiVisibility === 0 /* Visible */ || v.uiVisibility === 1 /* Hidden */) && (v.modifier === void 0 || v.modifier === 0 /* Open */ || v.modifier === 1 /* Abstract */ || v.modifier === 2 /* Sealed */) && (v.allowedStorage === void 0 || isClassAllowedStorage(v.allowedStorage)) && (v.allowedStorageKeys === void 0 || Array.isArray(v.allowedStorageKeys) && v.allowedStorageKeys.every((key) => typeof key === "string")) && (v.implementsInterfaceArguments === void 0 || isInterfaceArgumentsById(v.implementsInterfaceArguments)) && (v.genericParams === void 0 || Array.isArray(v.genericParams) && v.genericParams.every(isGenericParamDeclaration)) && (v.extendsGenericBindings === void 0 || isGenericBindingsRecord(v.extendsGenericBindings)) && (v.constructorIds === void 0 || Array.isArray(v.constructorIds) && v.constructorIds.every(
6781
+ )) && (v.uiVisibility === void 0 || v.uiVisibility === 0 /* Visible */ || v.uiVisibility === 1 /* Hidden */) && (v.modifier === void 0 || v.modifier === 0 /* Open */ || v.modifier === 1 /* Abstract */ || v.modifier === 2 /* Sealed */ || v.modifier === 3 /* Closed */) && (v.allowedStorage === void 0 || isClassAllowedStorage(v.allowedStorage)) && (v.allowedStorageKeys === void 0 || Array.isArray(v.allowedStorageKeys) && v.allowedStorageKeys.every((key) => typeof key === "string")) && (v.implementsInterfaceArguments === void 0 || isInterfaceArgumentsById(v.implementsInterfaceArguments)) && (v.genericParams === void 0 || Array.isArray(v.genericParams) && v.genericParams.every(isGenericParamDeclaration)) && (v.extendsGenericBindings === void 0 || isGenericBindingsRecord(v.extendsGenericBindings)) && (v.constructorIds === void 0 || Array.isArray(v.constructorIds) && v.constructorIds.every(
6695
6782
  (constructorId) => typeof constructorId === "string" && constructorId.length > 0
6696
6783
  ) && new Set(v.constructorIds).size === v.constructorIds.length) && (v.requiredConstructorId === void 0 || typeof v.requiredConstructorId === "string" && v.requiredConstructorId.length > 0 && (v.constructorIds ?? []).length === 0) && (v.targetMemberId === void 0 || typeof v.targetMemberId === "string" && v.targetMemberId.length > 0) && (v.system === void 0 || isSystemMetadata(v.system));
6697
6784
  }
@@ -7294,8 +7381,8 @@ function derivedMemberValueId(memberId) {
7294
7381
  );
7295
7382
  }
7296
7383
  function virtualValueId(instanceRootId, sourceIdentity2) {
7297
- const identity = `${withoutSystemRecordIdPrefix(instanceRootId)}:${sourceIdentity2}`;
7298
- const bytes = SURROGATE_CODE_UNIT.test(identity) ? identity : virtualIdentityEncoder.encode(identity);
7384
+ const identity2 = `${withoutSystemRecordIdPrefix(instanceRootId)}:${sourceIdentity2}`;
7385
+ const bytes = SURROGATE_CODE_UNIT.test(identity2) ? identity2 : virtualIdentityEncoder.encode(identity2);
7299
7386
  return inSystemRecordNamespaceOf(
7300
7387
  instanceRootId,
7301
7388
  v5_default(bytes, virtualNamespaceBytes)
@@ -7416,23 +7503,23 @@ function decodePackedValueRow(row) {
7416
7503
  projectId: row.projectId,
7417
7504
  mapKey: row.mapKey
7418
7505
  };
7419
- const children = [];
7506
+ const children3 = [];
7420
7507
  const scope = {
7421
7508
  state,
7422
7509
  ownerId: row.id,
7423
7510
  ownerLabel: `value "${row.id}"`,
7424
7511
  constructionRootId: isCollapseStampedInstanceRoot(row) ? row.id : null
7425
7512
  };
7426
- const value = decodeContentField(row.value, "value", scope, children);
7513
+ const value = decodeContentField(row.value, "value", scope, children3);
7427
7514
  const constructorArgs = decodeContentField(
7428
7515
  isLiteralValueContent(row) ? row.constructorArgs : void 0,
7429
7516
  "constructorArgs",
7430
7517
  scope,
7431
- children
7518
+ children3
7432
7519
  );
7433
7520
  return {
7434
7521
  row: withDecodedContent(row, value, constructorArgs),
7435
- children,
7522
+ children: children3,
7436
7523
  packedChildIdsByParentId: state.edges
7437
7524
  };
7438
7525
  }
@@ -7442,12 +7529,12 @@ function canonicalPackedChildId(args) {
7442
7529
  if (args.sourceValueId.length === 0) return null;
7443
7530
  return virtualValueId(args.constructionRootId, args.sourceValueId);
7444
7531
  }
7445
- function decodeContentField(container, field, scope, children) {
7532
+ function decodeContentField(container, field, scope, children3) {
7446
7533
  if (!containerHoldsPackedEntry(container)) return null;
7447
7534
  if (Array.isArray(container)) {
7448
7535
  return {
7449
7536
  content: container.map(
7450
- (entry, index) => isPackedValueEnvelope(entry) ? decodeEnvelope(entry, `${field}[${index}]`, scope, children) : entry
7537
+ (entry, index) => isPackedValueEnvelope(entry) ? decodeEnvelope(entry, `${field}[${index}]`, scope, children3) : entry
7451
7538
  )
7452
7539
  };
7453
7540
  }
@@ -7459,12 +7546,12 @@ function decodeContentField(container, field, scope, children) {
7459
7546
  entry,
7460
7547
  `${field}[${JSON.stringify(key)}]`,
7461
7548
  scope,
7462
- children
7549
+ children3
7463
7550
  ) : entry;
7464
7551
  }
7465
7552
  return { content: decoded };
7466
7553
  }
7467
- function decodeEnvelope(envelope, position, scope, children) {
7554
+ function decodeEnvelope(envelope, position, scope, children3) {
7468
7555
  const label = `Packed value entry at ${scope.ownerLabel}.${position}`;
7469
7556
  const entry = envelope[PACKED_VALUE_ENTRY_KEY];
7470
7557
  assertDecodableEntry(entry, label);
@@ -7483,11 +7570,11 @@ function decodeEnvelope(envelope, position, scope, children) {
7483
7570
  constructionRootId: isCollapseStampedInstanceRoot(entry) ? id : scope.constructionRootId
7484
7571
  };
7485
7572
  const nested = [];
7486
- children.push(logicalChildRow(entry, id, childScope, nested));
7487
- children.push(...nested);
7573
+ children3.push(logicalChildRow(entry, id, childScope, nested));
7574
+ children3.push(...nested);
7488
7575
  return id;
7489
7576
  }
7490
- function logicalChildRow(entry, id, scope, children) {
7577
+ function logicalChildRow(entry, id, scope, children3) {
7491
7578
  const rowFields = {
7492
7579
  id,
7493
7580
  projectId: scope.state.projectId,
@@ -7498,12 +7585,12 @@ function logicalChildRow(entry, id, scope, children) {
7498
7585
  ...entry.sourceValueId === void 0 ? {} : { sourceValueId: entry.sourceValueId }
7499
7586
  };
7500
7587
  if (isInitValueContent(entry)) return { ...rowFields, init: entry.init };
7501
- const value = decodeContentField(entry.value, "value", scope, children);
7588
+ const value = decodeContentField(entry.value, "value", scope, children3);
7502
7589
  const constructorArgs = decodeContentField(
7503
7590
  entry.constructorArgs,
7504
7591
  "constructorArgs",
7505
7592
  scope,
7506
- children
7593
+ children3
7507
7594
  );
7508
7595
  return {
7509
7596
  ...rowFields,
@@ -7799,9 +7886,9 @@ function editChangeListenerSet(explicit, inherited, edit, options = { inheritedC
7799
7886
  if (edit.kind === "replace") {
7800
7887
  next = edit.targets;
7801
7888
  } else {
7802
- const identity = nsActionListenerIdentity(edit.target);
7889
+ const identity2 = nsActionListenerIdentity(edit.target);
7803
7890
  const index = current.findIndex(
7804
- (target) => nsActionListenerIdentity(target) === identity
7891
+ (target) => nsActionListenerIdentity(target) === identity2
7805
7892
  );
7806
7893
  if (edit.kind === "add") {
7807
7894
  if (index !== -1) return { changed: false };
@@ -7814,10 +7901,10 @@ function editChangeListenerSet(explicit, inherited, edit, options = { inheritedC
7814
7901
  const targets = [];
7815
7902
  const seen = /* @__PURE__ */ new Set();
7816
7903
  for (const target of next) {
7817
- const identity = nsActionListenerIdentity(target);
7818
- if (seen.has(identity))
7904
+ const identity2 = nsActionListenerIdentity(target);
7905
+ if (seen.has(identity2))
7819
7906
  throw new Error("A listener set cannot repeat a handler identity.");
7820
- seen.add(identity);
7907
+ seen.add(identity2);
7821
7908
  targets.push({ memberId: target.memberId, valueId: target.valueId });
7822
7909
  }
7823
7910
  if (targets.length === 0 && inherited.length === 0 && options.inheritedComplete) {
@@ -10501,11 +10588,11 @@ function openBindingTypeInfo(member, env, classes, members2) {
10501
10588
  for (const [parameterId, argument2] of Object.entries(
10502
10589
  declaredSlotArguments(resolved) ?? {}
10503
10590
  )) {
10504
- const argumentType = isForwardedGenericBinding(argument2) ? param(argument2.genericParamId) : nested(argument2.memberId);
10505
- if (argumentType === null) {
10591
+ const argumentType2 = isForwardedGenericBinding(argument2) ? param(argument2.genericParamId) : nested(argument2.memberId);
10592
+ if (argumentType2 === null) {
10506
10593
  return genericBindingTypeInfo(resolved, env, members2);
10507
10594
  }
10508
- typeArguments[parameterId] = argumentType;
10595
+ typeArguments[parameterId] = argumentType2;
10509
10596
  }
10510
10597
  const typeArgumentsField = Object.keys(typeArguments).length === 0 ? {} : { typeArguments };
10511
10598
  if (isInterfaceTypedMember(resolved)) {
@@ -11450,9 +11537,9 @@ function isNeoInterfaceMember(value) {
11450
11537
  };
11451
11538
  if (containsForbiddenMemberTypeInfo(fn.returnTypeInfo, own)) return false;
11452
11539
  if (!Array.isArray(fn.argumentTypes)) return false;
11453
- for (const argumentType of fn.argumentTypes) {
11454
- if (!isNSFunctionArgumentTypeInfo(argumentType)) return false;
11455
- if (containsForbiddenMemberTypeInfo(argumentType, own)) return false;
11540
+ for (const argumentType2 of fn.argumentTypes) {
11541
+ if (!isNSFunctionArgumentTypeInfo(argumentType2)) return false;
11542
+ if (containsForbiddenMemberTypeInfo(argumentType2, own)) return false;
11456
11543
  }
11457
11544
  if (fn.dispatch !== void 0 && fn.dispatch !== 0 /* Synchronous */ && fn.dispatch !== 1 /* Asynchronous */)
11458
11545
  return false;
@@ -17513,6 +17600,57 @@ var UncompiledInitializerRuntimeError = class extends NSGetterRuntimeError {
17513
17600
  valueId;
17514
17601
  };
17515
17602
 
17603
+ // ../packages/neoscript-runtime/src/neoscript/bitwise.ts
17604
+ function evaluateBitwiseOp(info, evaluate) {
17605
+ const { op, argPointers } = info;
17606
+ if (!isNeoScriptBitwiseOp(op))
17607
+ throw new NSGetterRuntimeError(
17608
+ `Unknown bitwise operation '${String(op)}'.`
17609
+ );
17610
+ if (!Array.isArray(argPointers))
17611
+ throw new NSGetterRuntimeError(
17612
+ `Bitwise ${op} requires an argument pointer array.`
17613
+ );
17614
+ const arity = neoScriptBitwiseOpArity(op);
17615
+ if (argPointers.length !== arity)
17616
+ throw new NSGetterRuntimeError(
17617
+ `Bitwise ${op} requires ${arity} arguments; got ${argPointers.length}.`
17618
+ );
17619
+ const operand = (index) => {
17620
+ const value = evaluate(argPointers[index]);
17621
+ if (typeof value !== "number")
17622
+ throw new NSGetterRuntimeError(
17623
+ `Bitwise ${op} operand ${index + 1} must be a number.`
17624
+ );
17625
+ if (!Number.isFinite(value))
17626
+ throw new NSGetterRuntimeError(
17627
+ `Bitwise ${op} operand ${index + 1} must be finite.`
17628
+ );
17629
+ if (!Number.isInteger(value))
17630
+ throw new NSGetterRuntimeError(
17631
+ `Bitwise ${op} operand ${index + 1} must be an integer.`
17632
+ );
17633
+ return value | 0;
17634
+ };
17635
+ const left = operand(0);
17636
+ if (op === "not") return ~left;
17637
+ const right = operand(1);
17638
+ switch (op) {
17639
+ case "and":
17640
+ return left & right;
17641
+ case "or":
17642
+ return left | right;
17643
+ case "xor":
17644
+ return left ^ right;
17645
+ case "shiftLeft":
17646
+ return left << right;
17647
+ case "shiftRight":
17648
+ return left >> right;
17649
+ case "shiftRightUnsigned":
17650
+ return left >>> right | 0;
17651
+ }
17652
+ }
17653
+
17516
17654
  // ../packages/neoscript-runtime/src/neoscript/vector-math.ts
17517
17655
  function evaluateVectorOp(info, evaluate) {
17518
17656
  if (!isNeoScriptVectorKind(info.kind)) {
@@ -19984,11 +20122,11 @@ function createEffectiveClassRelationResolver(args) {
19984
20122
  const childrenByClassId = /* @__PURE__ */ new Map();
19985
20123
  for (const schemaClass2 of args.classes) {
19986
20124
  if (schemaClass2.extendsClassId === void 0) continue;
19987
- const children = childrenByClassId.get(schemaClass2.extendsClassId);
19988
- if (children === void 0) {
20125
+ const children3 = childrenByClassId.get(schemaClass2.extendsClassId);
20126
+ if (children3 === void 0) {
19989
20127
  childrenByClassId.set(schemaClass2.extendsClassId, [schemaClass2.id]);
19990
20128
  } else {
19991
- children.push(schemaClass2.id);
20129
+ children3.push(schemaClass2.id);
19992
20130
  }
19993
20131
  }
19994
20132
  const ancestry = (classId) => {
@@ -22423,8 +22561,8 @@ function exportInitializerCollections(created, writes, ctx) {
22423
22561
  collectionEntriesAreReferences: assignedValues.has(value) ? false : void 0,
22424
22562
  collectionOwnerId
22425
22563
  });
22426
- const children = rows.filter((row) => row !== root);
22427
- return { root, children, declarations };
22564
+ const children3 = rows.filter((row) => row !== root);
22565
+ return { root, children: children3, declarations };
22428
22566
  };
22429
22567
  const adopt = (owner, rootId, rows, declarations) => {
22430
22568
  const groupId = constructorGroupForRow(owner.id, ctx);
@@ -22462,13 +22600,13 @@ function exportInitializerCollections(created, writes, ctx) {
22462
22600
  const record4 = { ...inlineFields.record };
22463
22601
  const encoded2 = { ...row, value: record4 };
22464
22602
  for (const [key, member2] of inlineFields.members) {
22465
- const { root: root2, children: children2, declarations: declarations2 } = encode(
22603
+ const { root: root2, children: children4, declarations: declarations2 } = encode(
22466
22604
  member2,
22467
22605
  inPlace(record4[key]),
22468
22606
  inlineFields.genericEnv
22469
22607
  );
22470
22608
  record4[key] = root2.id;
22471
- adopt(encoded2, root2.id, [root2, ...children2], declarations2);
22609
+ adopt(encoded2, root2.id, [root2, ...children4], declarations2);
22472
22610
  }
22473
22611
  return encoded2;
22474
22612
  }
@@ -22480,7 +22618,7 @@ function exportInitializerCollections(created, writes, ctx) {
22480
22618
  }
22481
22619
  const value = inPlace(row.value);
22482
22620
  if (!assignedValues.has(value) && !mutatedIds.has(row.id)) return row;
22483
- const { root, children, declarations } = encode(
22621
+ const { root, children: children3, declarations } = encode(
22484
22622
  member,
22485
22623
  value,
22486
22624
  rowGenericEnv(row, ctx),
@@ -22488,7 +22626,7 @@ function exportInitializerCollections(created, writes, ctx) {
22488
22626
  );
22489
22627
  const encoded = { ...row, value: root.value };
22490
22628
  declarations.delete(root.id);
22491
- adopt(encoded, root.id, children, declarations);
22629
+ adopt(encoded, root.id, children3, declarations);
22492
22630
  return encoded;
22493
22631
  });
22494
22632
  return [...exported, ...extra];
@@ -22899,9 +23037,9 @@ function ownedConstructorArgumentValues(row, ctx, readRow) {
22899
23037
  };
22900
23038
  for (let index = 0; index < constructor.argumentTypes.length; index += 1) {
22901
23039
  const parameterId = constructor.action.parameters[index + 2]?.id;
22902
- const argumentType = constructor.argumentTypes[index];
22903
- if (parameterId === void 0 || argumentType === void 0) continue;
22904
- collect(row.constructorArgs[parameterId], argumentType, parameterId);
23040
+ const argumentType2 = constructor.argumentTypes[index];
23041
+ if (parameterId === void 0 || argumentType2 === void 0) continue;
23042
+ collect(row.constructorArgs[parameterId], argumentType2, parameterId);
22905
23043
  }
22906
23044
  return owned;
22907
23045
  }
@@ -24627,9 +24765,9 @@ function evalActionListenerInstruction(ins, scope, ctx, options) {
24627
24765
  destination = resolved;
24628
24766
  }) : evalPointer(target, scope, ctx);
24629
24767
  const current = actionListenersOf(currentValue, () => `'${operator}' target`);
24630
- const identity = nsActionListenerIdentity(listener);
24768
+ const identity2 = nsActionListenerIdentity(listener);
24631
24769
  const present = current.some(
24632
- (entry) => nsActionListenerIdentity(entry) === identity
24770
+ (entry) => nsActionListenerIdentity(entry) === identity2
24633
24771
  );
24634
24772
  let listeners;
24635
24773
  if (ins.type === "addActionListener" /* addActionListener */) {
@@ -24641,7 +24779,7 @@ function evalActionListenerInstruction(ins, scope, ctx, options) {
24641
24779
  } else {
24642
24780
  if (!present) return;
24643
24781
  listeners = current.filter(
24644
- (entry) => nsActionListenerIdentity(entry) !== identity
24782
+ (entry) => nsActionListenerIdentity(entry) !== identity2
24645
24783
  );
24646
24784
  }
24647
24785
  const value = { listeners };
@@ -27124,6 +27262,30 @@ function evalPointerCore(pointer, scope, ctx, resultUsage = "value") {
27124
27262
  if (left !== null && left !== void 0) return left;
27125
27263
  return evalPointer(pointer.right, scope, ctx);
27126
27264
  }
27265
+ case "switchExpression" /* switchExpression */: {
27266
+ const selected = evalPointer(pointer.selector, scope, ctx);
27267
+ for (const arm of pointer.arms) {
27268
+ checkDeadline(ctx);
27269
+ const pattern = arm.pattern;
27270
+ let matches = pattern.kind === "discard";
27271
+ if (pattern.kind === "constant") {
27272
+ const constant = pattern.constant.value;
27273
+ matches = Array.isArray(constant) ? Array.isArray(selected) && constant.length === selected.length && constant.every((item, index) => item === selected[index]) : selected === constant;
27274
+ }
27275
+ if (pattern.kind === "type")
27276
+ matches = selected != null && runtimeTypeCheck(selected, pattern.checkType, ctx);
27277
+ if (!matches) continue;
27278
+ const child = createChildScope(scope);
27279
+ child.setLocal(pointer.selectorId, selected);
27280
+ if (pattern.kind === "type" && pattern.bindingId)
27281
+ child.setLocal(pattern.bindingId, selected);
27282
+ if (arm.guard && evalPointer(arm.guard, child, ctx) !== true) continue;
27283
+ return evalPointer(arm.value, child, ctx);
27284
+ }
27285
+ throw new NSGetterRuntimeError(
27286
+ "Switch expression is not exhaustive for the runtime value."
27287
+ );
27288
+ }
27127
27289
  case "conditional" /* conditional */: {
27128
27290
  const condition = evalPointer(pointer.condition, scope, ctx);
27129
27291
  return evalPointer(
@@ -28486,16 +28648,16 @@ function evalKeyOf(pointer, scope, ctx, onDestination) {
28486
28648
  if (Array.isArray(receiver)) {
28487
28649
  if (typeof key === "string") {
28488
28650
  const indexes4 = evaluatorIndexes(ctx);
28489
- let identity = indexes4.listIdentityByArray.get(receiver);
28490
- if (identity === void 0) {
28491
- identity = /* @__PURE__ */ new Map();
28651
+ let identity2 = indexes4.listIdentityByArray.get(receiver);
28652
+ if (identity2 === void 0) {
28653
+ identity2 = /* @__PURE__ */ new Map();
28492
28654
  for (let i = 0; i < receiver.length; i += 1) {
28493
28655
  const valueId = receiver[i];
28494
- if (typeof valueId === "string") identity.set(valueId, i);
28656
+ if (typeof valueId === "string") identity2.set(valueId, i);
28495
28657
  }
28496
- indexes4.listIdentityByArray.set(receiver, identity);
28658
+ indexes4.listIdentityByArray.set(receiver, identity2);
28497
28659
  }
28498
- const position = identity.get(key);
28660
+ const position = identity2.get(key);
28499
28661
  if (position === void 0) {
28500
28662
  throw new NSGetterRuntimeError(`List value id not found: ${key}`);
28501
28663
  }
@@ -31114,6 +31276,11 @@ function evalFunction(fn, scope, ctx) {
31114
31276
  }
31115
31277
  case "mathOp" /* mathOp */:
31116
31278
  return evalMathOp(fn.info, scope, ctx);
31279
+ case "bitwiseOp" /* bitwiseOp */:
31280
+ return evaluateBitwiseOp(
31281
+ fn.info,
31282
+ (pointer) => evalPointer(pointer, scope, ctx)
31283
+ );
31117
31284
  case "vectorOp" /* vectorOp */:
31118
31285
  return evaluateVectorOp(
31119
31286
  fn.info,
@@ -32648,10 +32815,10 @@ function runtimeValueReferencesVariable(value, variableId, visited = /* @__PURE_
32648
32815
  if (Reflect.get(value, "type") === "variable" /* variable */ && Reflect.get(value, "variableId") === variableId) {
32649
32816
  return true;
32650
32817
  }
32651
- const children = Object.values(Object.getOwnPropertyDescriptors(value)).filter(
32818
+ const children3 = Object.values(Object.getOwnPropertyDescriptors(value)).filter(
32652
32819
  (descriptor) => "value" in descriptor
32653
32820
  ).map((descriptor) => descriptor.value);
32654
- return children.some(
32821
+ return children3.some(
32655
32822
  (child) => runtimeValueReferencesVariable(child, variableId, visited)
32656
32823
  );
32657
32824
  }
@@ -33925,14 +34092,14 @@ function constructDeclaredClassValueWithinFrame(descriptor, record4, info, scope
33925
34092
  `Constructor '${record4.id}' has no compiled parameter for argument ${index}.`
33926
34093
  );
33927
34094
  }
33928
- const argumentType = record4.argumentTypes[index];
33929
- if (argumentType === void 0) {
34095
+ const argumentType2 = record4.argumentTypes[index];
34096
+ if (argumentType2 === void 0) {
33930
34097
  throw new NSGetterRuntimeError(
33931
34098
  `Constructor '${record4.id}' has no declared type for argument ${index}.`
33932
34099
  );
33933
34100
  }
33934
34101
  const resolvedArgumentType = substituteRuntimeTypeInfo(
33935
- argumentType,
34102
+ argumentType2,
33936
34103
  descriptor.instanceEnv,
33937
34104
  ctx
33938
34105
  );
@@ -33946,7 +34113,7 @@ function constructDeclaredClassValueWithinFrame(descriptor, record4, info, scope
33946
34113
  // Only collection rows carry a stamp from the settled member.
33947
34114
  member: resolvedArgumentType.type === 6 /* List */ || resolvedArgumentType.type === 28 /* Set */ || resolvedArgumentType.type === 5 /* Dictionary */ ? settledConstructorParameterMember(
33948
34115
  classId,
33949
- argumentType.name,
34116
+ argumentType2.name,
33950
34117
  record4.id,
33951
34118
  ctx
33952
34119
  ) : void 0,
@@ -34148,8 +34315,8 @@ function currentOwnedValueAttachments(valueId, ctx) {
34148
34315
  }
34149
34316
  const directlyBoundMembers = directlyBoundMembersOf(valueId, ctx);
34150
34317
  for (const member of directlyBoundMembers) {
34151
- const identity = isStaticMember(member) ? `static:${member.id}` : `member:${member.id}`;
34152
- add({ identity, label: identity });
34318
+ const identity2 = isStaticMember(member) ? `static:${member.id}` : `member:${member.id}`;
34319
+ add({ identity: identity2, label: identity2 });
34153
34320
  }
34154
34321
  if (row !== null) {
34155
34322
  const rootMember = rootMemberForValueRow(row, ctx);
@@ -34834,9 +35001,9 @@ function retainOnlyCreatedRowsReachableFrom(rootId, createdValues, ctx) {
34834
35001
  const childrenByContainerId = /* @__PURE__ */ new Map();
34835
35002
  for (const row of createdValues) {
34836
35003
  if (typeof row.containerId !== "string") continue;
34837
- const children = childrenByContainerId.get(row.containerId) ?? [];
34838
- children.push(row.id);
34839
- childrenByContainerId.set(row.containerId, children);
35004
+ const children3 = childrenByContainerId.get(row.containerId) ?? [];
35005
+ children3.push(row.id);
35006
+ childrenByContainerId.set(row.containerId, children3);
34840
35007
  }
34841
35008
  const reachable = /* @__PURE__ */ new Set();
34842
35009
  const visit = (id) => {
@@ -35524,6 +35691,40 @@ function recordWrittenEntry(collection, key, reference, ctx) {
35524
35691
  else keys.delete(String(key));
35525
35692
  }
35526
35693
 
35694
+ // ../packages/neoscript-language/src/type-tokens.ts
35695
+ function scanNeoScriptType(tokens, start) {
35696
+ const token = tokens[start];
35697
+ if (!token) return null;
35698
+ const primitive3 = (token.kind === "type" || token.kind === "keyword") && ["int", "float", "decimal", "bool", "string", "null"].includes(token.text);
35699
+ const collection = token.kind === "type" && ["Dictionary", "List", "Set"].includes(token.text);
35700
+ if (!primitive3 && !collection && !isExecutableIdentifier(token)) return null;
35701
+ let index = start + 1;
35702
+ if ((collection || isExecutableIdentifier(token)) && tokens[index]?.kind === "operator" && tokens[index]?.text === "<") {
35703
+ index = scanNeoScriptType(tokens, index + 1) ?? -1;
35704
+ if (index < 0) return null;
35705
+ while (tokens[index]?.kind === "punctuation" && tokens[index]?.text === ",") {
35706
+ index = scanNeoScriptType(tokens, index + 1) ?? -1;
35707
+ if (index < 0) return null;
35708
+ }
35709
+ if (tokens[index]?.kind !== "operator" || tokens[index]?.text !== ">") {
35710
+ return null;
35711
+ }
35712
+ index++;
35713
+ } else if (collection) {
35714
+ return null;
35715
+ }
35716
+ while (tokens[index]?.kind === "punctuation" && tokens[index]?.text === "[" && tokens[index + 1]?.kind === "punctuation" && tokens[index + 1]?.text === "]") {
35717
+ index += 2;
35718
+ }
35719
+ if (tokens[index]?.kind === "operator" && tokens[index]?.text === "?") {
35720
+ index++;
35721
+ }
35722
+ return index;
35723
+ }
35724
+ function isExecutableIdentifier(token) {
35725
+ return token.kind === "identifier" || token.kind === "type" && token.text !== "int" && token.text !== "float" && token.text !== "decimal" && token.text !== "bool" && token.text !== "string" && token.text !== "Dictionary" && token.text !== "List" && token.text !== "Set";
35726
+ }
35727
+
35527
35728
  // ../packages/neoscript-language/src/strict-ast.ts
35528
35729
  function expressionBodyStatements(body, voidContext) {
35529
35730
  const pos = body.start;
@@ -35640,14 +35841,36 @@ function clamp(value, minimum, maximum) {
35640
35841
  }
35641
35842
 
35642
35843
  // ../packages/neoscript-language/src/lexer.ts
35844
+ function expressionOperator(tokens, index) {
35845
+ const first = tokens[index];
35846
+ if (first?.text !== "<" && first?.text !== ">") return first;
35847
+ let text = first.text;
35848
+ let end = first;
35849
+ let result = first;
35850
+ for (let offset = 1; offset <= 2; offset++) {
35851
+ const next = tokens[index + offset];
35852
+ if (!next || next.kind !== "operator" || next.start !== end.end) break;
35853
+ text += next.text;
35854
+ if (!["<<", ">>", ">>>", "<<=", ">>=", ">>>="].includes(text)) break;
35855
+ end = next;
35856
+ result = {
35857
+ ...first,
35858
+ text,
35859
+ raw: text,
35860
+ end: next.end,
35861
+ range: { start: first.range.start, end: next.range.end }
35862
+ };
35863
+ }
35864
+ return result;
35865
+ }
35643
35866
  var KEYWORD_SET = new Set(NEOSCRIPT_KEYWORDS);
35644
35867
  var TYPE_SET = /* @__PURE__ */ new Set([
35645
35868
  ...NEOSCRIPT_PRIMITIVE_TYPES,
35646
35869
  ...NEOSCRIPT_BUILTIN_TYPES
35647
35870
  ]);
35648
- var OPERATORS = [...NEOSCRIPT_OPERATORS].sort(
35649
- (left, right) => right.length - left.length
35650
- );
35871
+ var OPERATORS = NEOSCRIPT_OPERATORS.filter(
35872
+ (op) => !/^(?:<<|>>)/.test(op)
35873
+ ).sort((left, right) => right.length - left.length);
35651
35874
  var OPERATORS_BY_FIRST_CHARACTER = /* @__PURE__ */ new Map();
35652
35875
  for (const operator of OPERATORS) {
35653
35876
  const first = operator[0];
@@ -35836,7 +36059,7 @@ function lex(sourceValue) {
35836
36059
  function scanInterpolatedString(start, endOffset, grammarTokens2) {
35837
36060
  let cursor = start + 2;
35838
36061
  let segmentStart = start;
35839
- const children = [];
36062
+ const children3 = [];
35840
36063
  while (cursor < endOffset) {
35841
36064
  const char = sourceValue[cursor] ?? "";
35842
36065
  const next = sourceValue[cursor + 1] ?? "";
@@ -35855,7 +36078,7 @@ function lex(sourceValue) {
35855
36078
  if (char === '"') {
35856
36079
  cursor++;
35857
36080
  tokens.push(makeToken("string", segmentStart, cursor));
35858
- emitInterpolation(start, cursor, children, grammarTokens2);
36081
+ emitInterpolation(start, cursor, children3, grammarTokens2);
35859
36082
  return cursor;
35860
36083
  }
35861
36084
  if (char === "\n" || char === "\r") break;
@@ -35865,12 +36088,12 @@ function lex(sourceValue) {
35865
36088
  }
35866
36089
  const open = interpolationHoleToken(cursor);
35867
36090
  tokens.push(open);
35868
- children.push(open);
36091
+ children3.push(open);
35869
36092
  const expressionStart = cursor + 1;
35870
36093
  const expressionEnd = findInterpolationEnd(expressionStart, endOffset);
35871
36094
  if (expressionEnd === null) {
35872
- scanRange(expressionStart, endOffset, true, children);
35873
- emitInterpolation(start, endOffset, children, grammarTokens2);
36095
+ scanRange(expressionStart, endOffset, true, children3);
36096
+ emitInterpolation(start, endOffset, children3, grammarTokens2);
35874
36097
  diagnostics.push({
35875
36098
  range: source.range(cursor, endOffset),
35876
36099
  severity: "error",
@@ -35881,10 +36104,10 @@ function lex(sourceValue) {
35881
36104
  });
35882
36105
  return endOffset;
35883
36106
  }
35884
- scanRange(expressionStart, expressionEnd, true, children);
36107
+ scanRange(expressionStart, expressionEnd, true, children3);
35885
36108
  const close = interpolationHoleToken(expressionEnd);
35886
36109
  tokens.push(close);
35887
- children.push(close);
36110
+ children3.push(close);
35888
36111
  cursor = expressionEnd + 1;
35889
36112
  segmentStart = cursor;
35890
36113
  continue;
@@ -35894,7 +36117,7 @@ function lex(sourceValue) {
35894
36117
  if (segmentStart < cursor) {
35895
36118
  tokens.push(makeToken("string", segmentStart, cursor));
35896
36119
  }
35897
- emitInterpolation(start, cursor, children, grammarTokens2);
36120
+ emitInterpolation(start, cursor, children3, grammarTokens2);
35898
36121
  diagnostics.push({
35899
36122
  range: source.range(start, cursor),
35900
36123
  severity: "error",
@@ -35905,10 +36128,10 @@ function lex(sourceValue) {
35905
36128
  });
35906
36129
  return cursor;
35907
36130
  }
35908
- function emitInterpolation(start, end, children, grammarTokens2) {
36131
+ function emitInterpolation(start, end, children3, grammarTokens2) {
35909
36132
  grammarTokens2.push({
35910
36133
  ...makeToken("string", start, end, void 0, "interpolated"),
35911
- children
36134
+ children: children3
35912
36135
  });
35913
36136
  }
35914
36137
  function scanTripleString(start, endOffset, grammarTokens2) {
@@ -36122,6 +36345,16 @@ var Parser = class _Parser {
36122
36345
  if (!token) throw new Error("NeoScript parser received no EOF token.");
36123
36346
  return token;
36124
36347
  }
36348
+ peekOperator() {
36349
+ return expressionOperator(this.tokens, this.i) ?? this.peek();
36350
+ }
36351
+ nextOperator() {
36352
+ const operator = this.peekOperator();
36353
+ do {
36354
+ this.next();
36355
+ } while (this.peek().start < operator.end);
36356
+ return operator;
36357
+ }
36125
36358
  /** Consume and return the current token. */
36126
36359
  next() {
36127
36360
  const t = this.tokens[this.i];
@@ -36136,7 +36369,7 @@ var Parser = class _Parser {
36136
36369
  expect(kind, text) {
36137
36370
  const t = this.peek();
36138
36371
  if (!tokenMatches(t, kind, text)) {
36139
- if (this.recoverFlow && kind === "punctuation" && (text === ";" || text === "}" && t.kind === "eof")) {
36372
+ if (this.recoverFlow && kind === "punctuation" && (text === ";" || text === "}" && t.kind === "eof" || text === ")" && (t.kind === "eof" || t.text === "}" || t.text === ";"))) {
36140
36373
  return {
36141
36374
  ...t,
36142
36375
  kind,
@@ -36161,7 +36394,7 @@ var Parser = class _Parser {
36161
36394
  const token = this.peek();
36162
36395
  const afterLineBreak = token.range.start.line > this.peek(-1).range.end.line;
36163
36396
  const nextStatement = token.text === "var" && this.peek(1).kind === "identifier" || afterLineBreak && this.peek(1).text === "=";
36164
- if (this.recoverFlow && (nextStatement || !isIdentifier(token) && token.kind !== "type" && token.kind !== "keyword" || token.text === "return")) {
36397
+ if (this.recoverFlow && (nextStatement || !isExecutableIdentifier(token) && token.kind !== "type" && token.kind !== "keyword" || token.text === "return")) {
36165
36398
  const previous = this.peek(-1);
36166
36399
  return {
36167
36400
  ...previous,
@@ -36173,7 +36406,7 @@ var Parser = class _Parser {
36173
36406
  range: { start: previous.range.end, end: previous.range.end }
36174
36407
  };
36175
36408
  }
36176
- if (isIdentifier(token) || (token.kind === "keyword" || token.kind === "type") && (token.text === "native" || isValidNeoProjectMemberIdentifier(token.text))) {
36409
+ if (isExecutableIdentifier(token) || (token.kind === "keyword" || token.kind === "type") && (token.text === "native" || isValidNeoProjectMemberIdentifier(token.text))) {
36177
36410
  return this.next();
36178
36411
  }
36179
36412
  throw new CompileError(
@@ -36312,8 +36545,8 @@ var Parser = class _Parser {
36312
36545
  pos: at(t)
36313
36546
  };
36314
36547
  }
36315
- if (isAssignmentOp(this.peek())) {
36316
- const opTok = this.next();
36548
+ if (isAssignmentOp(this.peekOperator())) {
36549
+ const opTok = this.nextOperator();
36317
36550
  const value = this.parseExpr();
36318
36551
  this.expect("punctuation", ";");
36319
36552
  return {
@@ -36463,7 +36696,7 @@ var Parser = class _Parser {
36463
36696
  const type2 = this.peek();
36464
36697
  const name = this.peek(1);
36465
36698
  const close = this.peek(2);
36466
- if (type2.kind !== "type" || type2.text !== "string" || !isIdentifier(name) || close.kind !== "punctuation" || close.text !== ")") {
36699
+ if (type2.kind !== "type" || type2.text !== "string" || !isExecutableIdentifier(name) || close.kind !== "punctuation" || close.text !== ")") {
36467
36700
  throw new CompileError(
36468
36701
  "NeoScript catch parameters must have the form `catch (string name)`.",
36469
36702
  at(type2)
@@ -36560,7 +36793,7 @@ var Parser = class _Parser {
36560
36793
  };
36561
36794
  }
36562
36795
  const target = this.parseExpr();
36563
- const operator = this.peek();
36796
+ const operator = this.peekOperator();
36564
36797
  if (isIncrementOp(operator)) {
36565
36798
  this.next();
36566
36799
  return {
@@ -36577,7 +36810,7 @@ var Parser = class _Parser {
36577
36810
  at(operator)
36578
36811
  );
36579
36812
  }
36580
- this.next();
36813
+ this.nextOperator();
36581
36814
  return {
36582
36815
  kind: "assign",
36583
36816
  target,
@@ -36628,7 +36861,7 @@ var Parser = class _Parser {
36628
36861
  }
36629
36862
  parseVarDecl(terminated = true) {
36630
36863
  const startPos = at(this.peek());
36631
- const inferred = isIdentifier(this.peek()) && this.peek().text === NEOSCRIPT_INFERRED_LOCAL_KEYWORD;
36864
+ const inferred = isExecutableIdentifier(this.peek()) && this.peek().text === NEOSCRIPT_INFERRED_LOCAL_KEYWORD;
36632
36865
  let type2;
36633
36866
  if (inferred) {
36634
36867
  this.next();
@@ -36663,8 +36896,8 @@ var Parser = class _Parser {
36663
36896
  */
36664
36897
  looksLikeVarDecl() {
36665
36898
  const t = this.peek();
36666
- if (isIdentifier(t) && t.text === NEOSCRIPT_INFERRED_LOCAL_KEYWORD) {
36667
- return isIdentifier(this.peek(1));
36899
+ if (isExecutableIdentifier(t) && t.text === NEOSCRIPT_INFERRED_LOCAL_KEYWORD) {
36900
+ return isExecutableIdentifier(this.peek(1));
36668
36901
  }
36669
36902
  if (t.kind === "type" && (t.text === "int" || t.text === "float" || t.text === "decimal" || t.text === "bool" || t.text === "string")) {
36670
36903
  return true;
@@ -36675,11 +36908,11 @@ var Parser = class _Parser {
36675
36908
  if (t.kind === "type" && (t.text === "List" || t.text === "Set") && this.peek(1).kind === "operator" && this.peek(1).text === "<") {
36676
36909
  return true;
36677
36910
  }
36678
- if (!isIdentifier(t)) return false;
36911
+ if (!isExecutableIdentifier(t)) return false;
36679
36912
  const end = this.typeEnd();
36680
36913
  const name = this.tokens[end];
36681
36914
  const equals = this.tokens[end + 1];
36682
- return end >= 0 && name !== void 0 && isIdentifier(name) && equals?.kind === "operator" && equals.text === "=";
36915
+ return end >= 0 && name !== void 0 && isExecutableIdentifier(name) && equals?.kind === "operator" && equals.text === "=";
36683
36916
  }
36684
36917
  /**
36685
36918
  * Token index just past the type that starts at the cursor, or -1 when the
@@ -36765,7 +36998,7 @@ var Parser = class _Parser {
36765
36998
  pos: startPos
36766
36999
  };
36767
37000
  }
36768
- } else if (isIdentifier(t)) {
37001
+ } else if (isExecutableIdentifier(t)) {
36769
37002
  this.next();
36770
37003
  const typeArguments = [];
36771
37004
  if (this.eat("operator", "<")) {
@@ -36899,14 +37132,44 @@ var Parser = class _Parser {
36899
37132
  return left;
36900
37133
  }
36901
37134
  parseLogicalAnd() {
36902
- let left = this.parseEquality();
37135
+ let left = this.parseBitwiseOr();
36903
37136
  while (this.peek().kind === "operator" && this.peek().text === "&&") {
36904
37137
  const opTok = this.next();
36905
- const right = this.parseEquality();
37138
+ const right = this.parseBitwiseOr();
36906
37139
  left = makeBinary("&&", left, right, at(opTok));
36907
37140
  }
36908
37141
  return left;
36909
37142
  }
37143
+ parseBitwiseOr() {
37144
+ return this.parseBitwiseLevel("|", () => this.parseBitwiseXor());
37145
+ }
37146
+ parseBitwiseXor() {
37147
+ return this.parseBitwiseLevel("^", () => this.parseBitwiseAnd());
37148
+ }
37149
+ parseBitwiseAnd() {
37150
+ return this.parseBitwiseLevel("&", () => this.parseEquality());
37151
+ }
37152
+ parseBitwiseLevel(operator, operand) {
37153
+ let left = operand();
37154
+ while (this.peek().text === operator) {
37155
+ const token = this.next();
37156
+ left = makeBinary(operator, left, operand(), at(token));
37157
+ }
37158
+ return left;
37159
+ }
37160
+ parseShift() {
37161
+ let left = this.parseAdditive();
37162
+ while (["<<", ">>", ">>>"].includes(this.peekOperator().text)) {
37163
+ const token = this.nextOperator();
37164
+ left = makeBinary(
37165
+ asASTBinaryOp(token.text),
37166
+ left,
37167
+ this.parseAdditive(),
37168
+ at(token)
37169
+ );
37170
+ }
37171
+ return left;
37172
+ }
36910
37173
  parseEquality() {
36911
37174
  let left = this.parseComparison();
36912
37175
  while (true) {
@@ -36940,10 +37203,10 @@ var Parser = class _Parser {
36940
37203
  }
36941
37204
  }
36942
37205
  parseComparison() {
36943
- let left = this.parseAdditive();
36944
- while (this.peek().kind === "operator" && (this.peek().text === "<" || this.peek().text === ">" || this.peek().text === "<=" || this.peek().text === ">=")) {
36945
- const opTok = this.next();
36946
- const right = this.parseAdditive();
37206
+ let left = this.parseShift();
37207
+ while (this.peekOperator().kind === "operator" && (this.peekOperator().text === "<" || this.peekOperator().text === ">" || this.peekOperator().text === "<=" || this.peekOperator().text === ">=")) {
37208
+ const opTok = this.nextOperator();
37209
+ const right = this.parseShift();
36947
37210
  left = makeBinary(asASTBinaryOp(opTok.text), left, right, at(opTok));
36948
37211
  }
36949
37212
  return left;
@@ -36958,17 +37221,65 @@ var Parser = class _Parser {
36958
37221
  return left;
36959
37222
  }
36960
37223
  parseMultiplicative() {
36961
- let left = this.parseUnary();
37224
+ let left = this.parseSwitchExpression();
36962
37225
  while (this.peek().kind === "operator" && (this.peek().text === "*" || this.peek().text === "/" || this.peek().text === "%")) {
36963
37226
  const opTok = this.next();
36964
- const right = this.parseUnary();
37227
+ const right = this.parseSwitchExpression();
36965
37228
  left = makeBinary(asASTBinaryOp(opTok.text), left, right, at(opTok));
36966
37229
  }
36967
37230
  return left;
36968
37231
  }
37232
+ parseSwitchExpression() {
37233
+ let selector = this.parseUnary();
37234
+ while (this.peek().text === "switch") {
37235
+ const token = this.next();
37236
+ this.expect("punctuation", "{");
37237
+ const arms = [];
37238
+ while (this.peek().text !== "}") {
37239
+ const start = this.peek();
37240
+ let pattern;
37241
+ if (start.text === "_") {
37242
+ this.next();
37243
+ pattern = { kind: "discard", pos: at(start) };
37244
+ } else {
37245
+ const saved = this.i;
37246
+ const type2 = start.text !== "null" && this.typeEnd() >= 0 ? this.parseType() : null;
37247
+ if (type2 && this.peek().text !== "." && (this.peek().text === "=>" || this.peek().text === "when" || this.peek().kind === "identifier")) {
37248
+ const binding = this.peek().kind === "identifier" && this.peek().text !== "when" ? this.next().text : null;
37249
+ pattern = {
37250
+ kind: "type",
37251
+ type: type2,
37252
+ bindingName: binding === "_" ? null : binding,
37253
+ pos: at(start)
37254
+ };
37255
+ } else {
37256
+ this.i = saved;
37257
+ pattern = {
37258
+ kind: "constant",
37259
+ expression: this.parseUnary(),
37260
+ pos: at(start)
37261
+ };
37262
+ }
37263
+ }
37264
+ let guard = null;
37265
+ if (this.peek().text === "when") {
37266
+ this.next();
37267
+ guard = this.parseExpr();
37268
+ }
37269
+ this.expect("operator", "=>");
37270
+ const value = this.parseExpr();
37271
+ arms.push({ pattern, guard, value, pos: at(start) });
37272
+ if (this.peek().text !== ",") break;
37273
+ this.next();
37274
+ }
37275
+ this.expect("punctuation", "}");
37276
+ selector = { kind: "switchExpression", selector, arms, pos: at(token) };
37277
+ }
37278
+ return selector;
37279
+ }
36969
37280
  parseUnary() {
36970
37281
  const t = this.peek();
36971
- if (t.kind === "operator" && (t.text === "!" || t.text === "-")) {
37282
+ if (t.kind === "operator" && (t.text === "!" || t.text === "-" || t.text === "~")) {
36972
37283
  this.next();
36973
37284
  const operand = this.parseUnary();
36974
37285
  return { kind: "unary", op: t.text, operand, pos: at(t) };
@@ -37099,10 +37410,10 @@ var Parser = class _Parser {
37099
37410
  genericStaticMemberName() {
37100
37411
  const open = this.tokens[this.i];
37101
37412
  if (open?.kind !== "operator" || open.text !== "<") return null;
37102
- let index = this.scanType(this.i + 1);
37413
+ let index = scanNeoScriptType(this.tokens, this.i + 1);
37103
37414
  if (index === null) return null;
37104
37415
  while (this.tokens[index]?.kind === "punctuation" && this.tokens[index]?.text === ",") {
37105
- index = this.scanType(index + 1);
37416
+ index = scanNeoScriptType(this.tokens, index + 1);
37106
37417
  if (index === null) return null;
37107
37418
  }
37108
37419
  const close = this.tokens[index];
@@ -37110,53 +37421,21 @@ var Parser = class _Parser {
37110
37421
  const member = this.tokens[index + 2];
37111
37422
  if (close?.kind !== "operator" || close.text !== ">") return null;
37112
37423
  if (dot?.kind !== "punctuation" || dot.text !== ".") return null;
37113
- return member && isIdentifier(member) ? member.text : null;
37424
+ return member && isExecutableIdentifier(member) ? member.text : null;
37114
37425
  }
37115
37426
  looksLikeGenericCall() {
37116
37427
  const open = this.tokens[this.i];
37117
37428
  if (open?.kind !== "operator" || open.text !== "<") return false;
37118
- let index = this.scanType(this.i + 1);
37429
+ let index = scanNeoScriptType(this.tokens, this.i + 1);
37119
37430
  if (index === null) return false;
37120
37431
  while (this.tokens[index]?.kind === "punctuation" && this.tokens[index]?.text === ",") {
37121
- index = this.scanType(index + 1);
37432
+ index = scanNeoScriptType(this.tokens, index + 1);
37122
37433
  if (index === null) return false;
37123
37434
  }
37124
37435
  const close = this.tokens[index];
37125
37436
  const call = this.tokens[index + 1];
37126
37437
  return close?.kind === "operator" && close.text === ">" && call?.kind === "punctuation" && call.text === "(";
37127
37438
  }
37128
- /** Returns the first token after one syntactically complete type. */
37129
- scanType(start) {
37130
- const token = this.tokens[start];
37131
- if (!token) return null;
37132
- const primitive3 = (token.kind === "type" || token.kind === "keyword") && ["int", "float", "decimal", "bool", "string", "null"].includes(
37133
- token.text
37134
- );
37135
- const collection = token.kind === "type" && ["Dictionary", "List", "Set"].includes(token.text);
37136
- if (!primitive3 && !collection && !isIdentifier(token)) return null;
37137
- let index = start + 1;
37138
- if ((collection || isIdentifier(token)) && this.tokens[index]?.kind === "operator" && this.tokens[index]?.text === "<") {
37139
- index = this.scanType(index + 1) ?? -1;
37140
- if (index < 0) return null;
37141
- while (this.tokens[index]?.kind === "punctuation" && this.tokens[index]?.text === ",") {
37142
- index = this.scanType(index + 1) ?? -1;
37143
- if (index < 0) return null;
37144
- }
37145
- if (this.tokens[index]?.kind !== "operator" || this.tokens[index]?.text !== ">") {
37146
- return null;
37147
- }
37148
- index++;
37149
- } else if (collection) {
37150
- return null;
37151
- }
37152
- while (this.tokens[index]?.kind === "punctuation" && this.tokens[index]?.text === "[" && this.tokens[index + 1]?.kind === "punctuation" && this.tokens[index + 1]?.text === "]") {
37153
- index += 2;
37154
- }
37155
- if (this.tokens[index]?.kind === "operator" && this.tokens[index]?.text === "?") {
37156
- index++;
37157
- }
37158
- return index;
37159
- }
37160
37439
  parseCallArgs() {
37161
37440
  const args = [];
37162
37441
  const argumentNames = [];
@@ -37223,9 +37502,9 @@ var Parser = class _Parser {
37223
37502
  pos: at(t)
37224
37503
  };
37225
37504
  }
37226
- if (isIdentifier(t) && t.text === NEOSCRIPT_CONSTRUCTOR_KEYWORD) {
37505
+ if (isExecutableIdentifier(t) && t.text === NEOSCRIPT_CONSTRUCTOR_KEYWORD) {
37227
37506
  this.next();
37228
- const classToken = isIdentifier(this.peek()) ? this.next() : null;
37507
+ const classToken = isExecutableIdentifier(this.peek()) ? this.next() : null;
37229
37508
  const className = classToken?.text ?? null;
37230
37509
  const typeArguments = [];
37231
37510
  if (this.eat("operator", "<")) {
@@ -37334,7 +37613,7 @@ var Parser = class _Parser {
37334
37613
  this.expect("punctuation", ")");
37335
37614
  return inner;
37336
37615
  }
37337
- if (t.text === "base" || isIdentifier(t) || (t.kind === "keyword" || t.kind === "type") && isValidNeoProjectIdentifier(t.text)) {
37616
+ if (t.text === "base" || isExecutableIdentifier(t) || (t.kind === "keyword" || t.kind === "type") && isValidNeoProjectIdentifier(t.text)) {
37338
37617
  this.next();
37339
37618
  return { kind: "ident", name: t.text, pos: at(t) };
37340
37619
  }
@@ -37461,8 +37740,8 @@ var Parser = class _Parser {
37461
37740
  value: null
37462
37741
  });
37463
37742
  }
37464
- if (isAssignmentOp(this.peek())) {
37465
- const opTok = this.next();
37743
+ if (isAssignmentOp(this.peekOperator())) {
37744
+ const opTok = this.nextOperator();
37466
37745
  return this.expressionBody(start, expr, {
37467
37746
  op: opTok.text,
37468
37747
  value: this.parseExpr()
@@ -37484,8 +37763,8 @@ var Parser = class _Parser {
37484
37763
  */
37485
37764
  parseLambdaParam() {
37486
37765
  const startPos = at(this.peek());
37487
- const afterType = this.scanType(this.i);
37488
- if (afterType !== null && this.tokens[afterType] !== void 0 && isIdentifier(this.tokens[afterType])) {
37766
+ const afterType = scanNeoScriptType(this.tokens, this.i);
37767
+ if (afterType !== null && this.tokens[afterType] !== void 0 && isExecutableIdentifier(this.tokens[afterType])) {
37489
37768
  const type2 = this.parseType();
37490
37769
  const name2 = this.expect("identifier");
37491
37770
  return { type: type2, name: name2.text, pos: startPos };
@@ -37536,17 +37815,17 @@ var Parser = class _Parser {
37536
37815
  return { key, value, pos };
37537
37816
  }
37538
37817
  buildInterpLiteral(token) {
37539
- const children = token.children ?? [];
37818
+ const children3 = token.children ?? [];
37540
37819
  const parts = [];
37541
37820
  let literalStart = token.start + 2;
37542
- for (let index = 0; index < children.length; index++) {
37543
- const open = children[index];
37821
+ for (let index = 0; index < children3.length; index++) {
37822
+ const open = children3[index];
37544
37823
  if (!open?.interpolationHole || open.text !== "{") continue;
37545
37824
  let closeIndex = index + 1;
37546
- while (closeIndex < children.length && (children[closeIndex]?.interpolationHole !== true || children[closeIndex]?.text !== "}")) {
37825
+ while (closeIndex < children3.length && (children3[closeIndex]?.interpolationHole !== true || children3[closeIndex]?.text !== "}")) {
37547
37826
  closeIndex++;
37548
37827
  }
37549
- const close = children[closeIndex];
37828
+ const close = children3[closeIndex];
37550
37829
  if (!close) {
37551
37830
  throw new CompileError(
37552
37831
  "Unterminated interpolation expression",
@@ -37554,7 +37833,7 @@ var Parser = class _Parser {
37554
37833
  );
37555
37834
  }
37556
37835
  pushInterpolationText(parts, token, literalStart, open.start);
37557
- const expressionTokens = children.slice(index + 1, closeIndex).filter((candidate) => candidate.kind !== "comment");
37836
+ const expressionTokens = children3.slice(index + 1, closeIndex).filter((candidate) => candidate.kind !== "comment");
37558
37837
  const inner = new _Parser([
37559
37838
  ...expressionTokens,
37560
37839
  eofToken(close.start, close.range.start)
@@ -37595,6 +37874,12 @@ function asASTBinaryOp(text) {
37595
37874
  case ">":
37596
37875
  case "<=":
37597
37876
  case ">=":
37877
+ case "&":
37878
+ case "|":
37879
+ case "^":
37880
+ case "<<":
37881
+ case ">>":
37882
+ case ">>>":
37598
37883
  case "&&":
37599
37884
  case "||":
37600
37885
  return text;
@@ -37648,13 +37933,10 @@ function at(token) {
37648
37933
  };
37649
37934
  }
37650
37935
  function tokenMatches(token, kind, text) {
37651
- return (kind === "identifier" ? isIdentifier(token) : token.kind === kind) && (text === void 0 || token.text === text);
37936
+ return (kind === "identifier" ? isExecutableIdentifier(token) : token.kind === kind) && (text === void 0 || token.text === text);
37652
37937
  }
37653
37938
  function isCallArgumentLabelToken(token) {
37654
- return isIdentifier(token) || token.kind === "keyword" && (token.text === "default" || isValidNeoProjectIdentifier(token.text));
37655
- }
37656
- function isIdentifier(token) {
37657
- return token.kind === "identifier" || token.kind === "type" && token.text !== "int" && token.text !== "float" && token.text !== "decimal" && token.text !== "bool" && token.text !== "string" && token.text !== "Dictionary" && token.text !== "List" && token.text !== "Set";
37939
+ return isExecutableIdentifier(token) || token.kind === "keyword" && (token.text === "default" || isValidNeoProjectIdentifier(token.text));
37658
37940
  }
37659
37941
  function pushInterpolationText(parts, token, start, end) {
37660
37942
  if (start >= end) return;
@@ -37683,7 +37965,7 @@ function positionWithinToken(token, offset) {
37683
37965
  return { line, column };
37684
37966
  }
37685
37967
  function isAssignmentOp(token) {
37686
- return token.kind === "operator" && (token.text === "=" || token.text === "+=" || token.text === "-=" || token.text === "*=" || token.text === "/=" || token.text === "%=");
37968
+ return token.kind === "operator" && (token.text === "=" || token.text === "+=" || token.text === "-=" || token.text === "*=" || token.text === "/=" || token.text === "%=" || token.text === "&=" || token.text === "|=" || token.text === "^=" || token.text === "<<=" || token.text === ">>=" || token.text === ">>>=");
37687
37969
  }
37688
37970
  function isIncrementOp(token) {
37689
37971
  return token.kind === "operator" && (token.text === "++" || token.text === "--");
@@ -38383,7 +38665,7 @@ function resolveMemberDeclaredTypeInfoInternal(member, members2, seen, ownerClas
38383
38665
  (candidate) => candidate.id === binding.memberId
38384
38666
  );
38385
38667
  if (argumentMember === void 0) return [];
38386
- const argumentType = resolveMemberDeclaredTypeInfoInternal(
38668
+ const argumentType2 = resolveMemberDeclaredTypeInfoInternal(
38387
38669
  argumentMember,
38388
38670
  members2,
38389
38671
  nextSeen,
@@ -38391,7 +38673,7 @@ function resolveMemberDeclaredTypeInfoInternal(member, members2, seen, ownerClas
38391
38673
  env,
38392
38674
  isClassConstrained
38393
38675
  );
38394
- return argumentType === null ? [] : [[genericParamId, argumentType]];
38676
+ return argumentType2 === null ? [] : [[genericParamId, argumentType2]];
38395
38677
  }
38396
38678
  )
38397
38679
  );
@@ -39185,11 +39467,11 @@ function indexChildrenByContainerId(rows) {
39185
39467
  const childrenByContainerId = /* @__PURE__ */ new Map();
39186
39468
  for (const row of rows.values()) {
39187
39469
  if (typeof row.containerId !== "string") continue;
39188
- const children = childrenByContainerId.get(row.containerId);
39189
- if (children === void 0) {
39470
+ const children3 = childrenByContainerId.get(row.containerId);
39471
+ if (children3 === void 0) {
39190
39472
  childrenByContainerId.set(row.containerId, [row]);
39191
39473
  } else {
39192
- children.push(row);
39474
+ children3.push(row);
39193
39475
  }
39194
39476
  }
39195
39477
  return childrenByContainerId;
@@ -39259,10 +39541,10 @@ function derivesContentFromMemberDefault(args) {
39259
39541
  }
39260
39542
  function projectNestedListenerEndpoint(id, descriptor, sourceRoot, targetRoot) {
39261
39543
  const raw = descriptor.sourceValueId ?? `path:${descriptor.memberId}:${descriptor.pathKey}`;
39262
- const derive = (root, identity) => claimVirtualIdentity({
39544
+ const derive = (root, identity2) => claimVirtualIdentity({
39263
39545
  claimedVirtualIds: /* @__PURE__ */ new Map(),
39264
39546
  instanceRootId: root,
39265
- rawSourceIdentity: identity,
39547
+ rawSourceIdentity: identity2,
39266
39548
  pathKey: descriptor.pathKey
39267
39549
  }).virtualId;
39268
39550
  if (derive(sourceRoot, raw) === id) return derive(targetRoot, raw);
@@ -39629,9 +39911,9 @@ function resolveVirtualInstanceGraph(args) {
39629
39911
  const locationsById = /* @__PURE__ */ new Map();
39630
39912
  const locationsByPath = /* @__PURE__ */ new Map();
39631
39913
  const childPathsByParentPath = new Map(
39632
- [...expansion.childPathsByParentPath].map(([path, children]) => [
39914
+ [...expansion.childPathsByParentPath].map(([path, children3]) => [
39633
39915
  path,
39634
- [...children]
39916
+ [...children3]
39635
39917
  ])
39636
39918
  );
39637
39919
  const visiting = /* @__PURE__ */ new Set();
@@ -39948,9 +40230,9 @@ function resolveVirtualInstanceGraph(args) {
39948
40230
  }
39949
40231
  spans.set(current.path, { start: sequence++, end: 0 });
39950
40232
  pending.push({ path: current.path, exit: true });
39951
- const children = expansion.childPathsByParentPath.get(current.path) ?? [];
39952
- for (let i = children.length - 1; i >= 0; i--)
39953
- pending.push({ path: children[i], exit: false });
40233
+ const children3 = expansion.childPathsByParentPath.get(current.path) ?? [];
40234
+ for (let i = children3.length - 1; i >= 0; i--)
40235
+ pending.push({ path: children3[i], exit: false });
39954
40236
  }
39955
40237
  ancestry = spans;
39956
40238
  }
@@ -44503,6 +44785,27 @@ function indexReferences(tokens, pairs, declarations, contextualKeywords, negati
44503
44785
  }
44504
44786
  continue;
44505
44787
  }
44788
+ if (token.text === "switch" && tokens[index + 1]?.text === "{") {
44789
+ const close = pairs.get(index + 1);
44790
+ if (close !== void 0) {
44791
+ let armStart = index + 2;
44792
+ for (let cursor = armStart; cursor < close; cursor++) {
44793
+ const nestedClose = pairs.get(cursor);
44794
+ if (nestedClose !== void 0 && nestedClose > cursor) {
44795
+ cursor = nestedClose;
44796
+ continue;
44797
+ }
44798
+ if (tokens[cursor]?.text !== ",") continue;
44799
+ const end2 = new Parser(tokens, armStart).typeEnd();
44800
+ if (end2 >= 0 && tokens[end2]?.kind === "identifier" && (tokens[end2 + 1]?.text === "=>" || tokens[end2 + 1]?.text === "when"))
44801
+ patternBindings.add(end2);
44802
+ armStart = cursor + 1;
44803
+ }
44804
+ const end = new Parser(tokens, armStart).typeEnd();
44805
+ if (end >= 0 && tokens[end]?.kind === "identifier" && (tokens[end + 1]?.text === "=>" || tokens[end + 1]?.text === "when"))
44806
+ patternBindings.add(end);
44807
+ }
44808
+ }
44506
44809
  if (token.kind !== "identifier" && token.text !== "base") continue;
44507
44810
  const previous = tokens[index - 1];
44508
44811
  const next = tokens[index + 1];
@@ -44850,6 +45153,500 @@ function analyzeNeoScriptSyntax(source, kind, lexed = lex(source)) {
44850
45153
  return { lexed, parsed: buildNeoScriptEditorIndex(lexed, kind) };
44851
45154
  }
44852
45155
 
45156
+ // ../packages/neoscript-language/src/switch-coverage.ts
45157
+ var childrenByProject = /* @__PURE__ */ new WeakMap();
45158
+ function children(project) {
45159
+ const cached = childrenByProject.get(project);
45160
+ if (cached) return cached;
45161
+ const result = /* @__PURE__ */ new Map();
45162
+ for (const type2 of project.typeById.values()) {
45163
+ if (type2.kind !== "class") continue;
45164
+ for (const base of type2.baseTypeIds ?? []) {
45165
+ const list = result.get(base);
45166
+ if (list) list.push(type2);
45167
+ else result.set(base, [type2]);
45168
+ }
45169
+ }
45170
+ childrenByProject.set(project, result);
45171
+ return result;
45172
+ }
45173
+ function combine(results) {
45174
+ if (results.includes("mismatch")) return "mismatch";
45175
+ return results.includes("unknown") ? "unknown" : "match";
45176
+ }
45177
+ function containsParameter(type2) {
45178
+ switch (type2.kind) {
45179
+ case "typeParameter":
45180
+ return true;
45181
+ case "named":
45182
+ return type2.typeArguments?.some(containsParameter) ?? false;
45183
+ case "list":
45184
+ case "set":
45185
+ return containsParameter(type2.elementType);
45186
+ case "dictionary":
45187
+ return containsParameter(type2.keyType) || containsParameter(type2.valueType);
45188
+ case "reference":
45189
+ return containsParameter(type2.target);
45190
+ default:
45191
+ return false;
45192
+ }
45193
+ }
45194
+ function unify(template, actual, bindings, project) {
45195
+ if (template.kind === "typeParameter") {
45196
+ const previous = bindings.get(template.id);
45197
+ if (template.nullable === true) {
45198
+ if (actual.nullable !== true) return "mismatch";
45199
+ if (!previous) return "unknown";
45200
+ const nullablePrevious = { ...previous, nullable: true };
45201
+ return isNeoScriptTypeAssignable(nullablePrevious, actual, project) && isNeoScriptTypeAssignable(actual, nullablePrevious, project) ? "match" : "mismatch";
45202
+ }
45203
+ if (!previous) {
45204
+ bindings.set(template.id, actual);
45205
+ return "match";
45206
+ }
45207
+ if (isNeoScriptTypeAssignable(previous, actual, project) && isNeoScriptTypeAssignable(actual, previous, project))
45208
+ return "match";
45209
+ return containsParameter(previous) || containsParameter(actual) ? "unknown" : "mismatch";
45210
+ }
45211
+ if (actual.kind === "typeParameter") return "unknown";
45212
+ if (template.kind !== actual.kind) return "mismatch";
45213
+ if (template.nullable === true !== (actual.nullable === true))
45214
+ return "mismatch";
45215
+ if (template.kind === "named" && actual.kind === "named") {
45216
+ if (template.typeId !== actual.typeId) return "mismatch";
45217
+ const left = template.typeArguments ?? [];
45218
+ const right = actual.typeArguments ?? [];
45219
+ if (left.length !== right.length) return "mismatch";
45220
+ return combine(
45221
+ left.map((item, index) => unify(item, right[index], bindings, project))
45222
+ );
45223
+ }
45224
+ if (template.kind === "list" && actual.kind === "list" || template.kind === "set" && actual.kind === "set")
45225
+ return unify(template.elementType, actual.elementType, bindings, project);
45226
+ if (template.kind === "dictionary" && actual.kind === "dictionary")
45227
+ return combine([
45228
+ unify(template.keyType, actual.keyType, bindings, project),
45229
+ unify(template.valueType, actual.valueType, bindings, project)
45230
+ ]);
45231
+ if (template.kind === "reference" && actual.kind === "reference")
45232
+ return unify(template.target, actual.target, bindings, project);
45233
+ return isNeoScriptTypeAssignable(template, actual, project) && isNeoScriptTypeAssignable(actual, template, project) ? "match" : "mismatch";
45234
+ }
45235
+ function typeShape(type2) {
45236
+ const nullable2 = type2.nullable === true;
45237
+ switch (type2.kind) {
45238
+ case "named":
45239
+ return [
45240
+ type2.kind,
45241
+ type2.typeId,
45242
+ nullable2,
45243
+ (type2.typeArguments ?? []).map(typeShape)
45244
+ ];
45245
+ case "primitive":
45246
+ return [type2.kind, type2.name, nullable2];
45247
+ case "typeParameter":
45248
+ return [type2.kind, type2.id, nullable2];
45249
+ case "list":
45250
+ case "set":
45251
+ return [
45252
+ type2.kind,
45253
+ nullable2,
45254
+ type2.ordered === true,
45255
+ typeShape(type2.elementType)
45256
+ ];
45257
+ case "dictionary":
45258
+ return [
45259
+ type2.kind,
45260
+ nullable2,
45261
+ typeShape(type2.keyType),
45262
+ typeShape(type2.valueType)
45263
+ ];
45264
+ case "reference":
45265
+ return [type2.kind, nullable2, typeShape(type2.target)];
45266
+ case "delegate":
45267
+ return [
45268
+ type2.kind,
45269
+ nullable2,
45270
+ typeShape(type2.returnType),
45271
+ type2.parameterTypes.map(typeShape)
45272
+ ];
45273
+ case "action":
45274
+ return [type2.kind, nullable2, type2.parameterTypes.map(typeShape)];
45275
+ }
45276
+ }
45277
+ function typeKey(type2) {
45278
+ return JSON.stringify(typeShape(type2));
45279
+ }
45280
+ var SwitchCoverage = class {
45281
+ constructor(project) {
45282
+ this.project = project;
45283
+ }
45284
+ project;
45285
+ constants = /* @__PURE__ */ new Set();
45286
+ types = /* @__PURE__ */ new Set();
45287
+ compoundPatterns = /* @__PURE__ */ new Map();
45288
+ discarded = false;
45289
+ add(pattern) {
45290
+ if (pattern.kind === "discard") this.discarded = true;
45291
+ else if (pattern.kind === "constant") this.constants.add(pattern.value);
45292
+ else {
45293
+ this.types.add(typeKey(pattern.type));
45294
+ const type2 = pattern.type;
45295
+ const variant2 = type2.kind === "named" && this.project.typeById.get(type2.typeId)?.name === "NeoVariant";
45296
+ if (type2.kind !== "named" || variant2) {
45297
+ const key = variant2 && type2.kind === "named" ? type2.typeId : type2.kind;
45298
+ const bucket = this.compoundPatterns.get(key);
45299
+ if (bucket) bucket.push(type2);
45300
+ else this.compoundPatterns.set(key, [type2]);
45301
+ }
45302
+ }
45303
+ }
45304
+ coversType(input) {
45305
+ if (this.discarded) return true;
45306
+ if (this.types.size === 0) return false;
45307
+ const type2 = { ...input, nullable: false };
45308
+ if (this.types.has(typeKey(type2))) return true;
45309
+ if (type2.kind === "typeParameter") {
45310
+ const bound = neoScriptMemberLookupType(type2);
45311
+ return bound.kind !== "typeParameter" && this.coversType(bound);
45312
+ }
45313
+ if (type2.kind === "named") {
45314
+ for (const ancestor of constructedSupertypes(type2, this.project)) {
45315
+ if (this.types.has(typeKey(ancestor))) return true;
45316
+ }
45317
+ for (const narrowed of Object.values(type2.narrowedInterfaces ?? {})) {
45318
+ if (this.coversType(narrowed)) return true;
45319
+ }
45320
+ }
45321
+ if (type2.kind === "primitive") {
45322
+ return type2.name === "int" && this.types.has(typeKey({ kind: "primitive", name: "float" }));
45323
+ }
45324
+ const bucket = type2.kind === "named" ? type2.typeId : type2.kind;
45325
+ for (const pattern of this.compoundPatterns.get(bucket) ?? []) {
45326
+ if (isNeoScriptTypeAssignable(type2, pattern, this.project)) return true;
45327
+ }
45328
+ if (type2.kind !== "reference") {
45329
+ for (const pattern of this.compoundPatterns.get("reference") ?? []) {
45330
+ if (isNeoScriptTypeAssignable(type2, pattern, this.project)) return true;
45331
+ }
45332
+ }
45333
+ return false;
45334
+ }
45335
+ subsumes(pattern, selector) {
45336
+ if (this.discarded) return true;
45337
+ if (pattern.kind === "discard") return false;
45338
+ if (pattern.kind === "constant")
45339
+ return this.constants.has(pattern.value) || pattern.value !== null && this.coversType(selector);
45340
+ return missingSwitchCases(pattern.type, this, this.project).length === 0;
45341
+ }
45342
+ };
45343
+ function missingSwitchCases(selector, coverage, project) {
45344
+ if (coverage.discarded) return [];
45345
+ const constants = coverage.constants;
45346
+ const missing = [];
45347
+ if (selector.nullable && !constants.has(null)) missing.push("null");
45348
+ const active = /* @__PURE__ */ new Set();
45349
+ const visit = (input) => {
45350
+ const type2 = { ...neoScriptMemberLookupType(input), nullable: false };
45351
+ if (coverage.coversType(type2)) return;
45352
+ if (type2.kind === "primitive" && type2.name === "bool") {
45353
+ if (!constants.has(false)) missing.push("false");
45354
+ if (!constants.has(true)) missing.push("true");
45355
+ return;
45356
+ }
45357
+ const definition = type2.kind === "named" ? project.typeById.get(type2.typeId) : void 0;
45358
+ if (definition?.kind === "enum") {
45359
+ for (const option of definition.members) {
45360
+ if (!constants.has(option.id))
45361
+ missing.push(`${definition.name}.${option.name}`);
45362
+ }
45363
+ return;
45364
+ }
45365
+ if (type2.kind !== "named" || !definition?.closed || active.has(type2.typeId)) {
45366
+ missing.push(`${formatType(type2, project)} (use a type or '_' fallback)`);
45367
+ return;
45368
+ }
45369
+ active.add(type2.typeId);
45370
+ const descendants = children(project).get(type2.typeId) ?? [];
45371
+ if (descendants.length === 0) missing.push(formatType(type2, project));
45372
+ for (const child of descendants) {
45373
+ const baseArguments = child.supertypeArguments?.[type2.typeId] ?? [];
45374
+ const actualArguments = type2.typeArguments ?? [];
45375
+ const bindings = /* @__PURE__ */ new Map();
45376
+ if (baseArguments.length !== actualArguments.length) {
45377
+ missing.push(formatType(type2, project));
45378
+ continue;
45379
+ }
45380
+ const matchArguments = () => combine(
45381
+ baseArguments.map(
45382
+ (argument2, index) => unify(argument2, actualArguments[index], bindings, project)
45383
+ )
45384
+ );
45385
+ let match = matchArguments();
45386
+ if (match === "unknown") match = matchArguments();
45387
+ if (match !== "match") {
45388
+ if (match === "unknown") missing.push(formatType(type2, project));
45389
+ continue;
45390
+ }
45391
+ const argumentsList2 = [];
45392
+ let nameable = true;
45393
+ for (const parameter3 of child.typeParameters ?? []) {
45394
+ const argument2 = bindings.get(parameter3.id ?? parameter3.name);
45395
+ if (!argument2) {
45396
+ nameable = false;
45397
+ break;
45398
+ }
45399
+ if (parameter3.type.kind === "typeParameter" && parameter3.type.constraint) {
45400
+ const bound = substituteNeoScriptTypeParameters(
45401
+ parameter3.type.constraint,
45402
+ (parameter4) => bindings.get(parameter4.id),
45403
+ project
45404
+ );
45405
+ if (!isNeoScriptTypeAssignable(argument2, bound, project)) {
45406
+ nameable = false;
45407
+ break;
45408
+ }
45409
+ }
45410
+ argumentsList2.push(argument2);
45411
+ }
45412
+ if (!nameable) {
45413
+ missing.push(formatType(type2, project));
45414
+ continue;
45415
+ }
45416
+ visit({
45417
+ kind: "named",
45418
+ typeId: child.id,
45419
+ ...argumentsList2.length ? { typeArguments: argumentsList2 } : {}
45420
+ });
45421
+ }
45422
+ active.delete(type2.typeId);
45423
+ };
45424
+ visit(selector);
45425
+ return [...new Set(missing)];
45426
+ }
45427
+
45428
+ // ../packages/neoscript-language/src/function-type-inference.ts
45429
+ function identity(type2) {
45430
+ const nullable2 = type2.nullable === true ? "?" : "";
45431
+ switch (type2.kind) {
45432
+ case "primitive":
45433
+ return `p:${type2.name}${nullable2}`;
45434
+ case "typeParameter":
45435
+ return `t:${type2.id}${nullable2}`;
45436
+ case "named":
45437
+ return `n:${type2.typeId}<${(type2.typeArguments ?? []).map(identity).join(",")}>${nullable2}`;
45438
+ case "list":
45439
+ case "set":
45440
+ return `${type2.kind}<${identity(type2.elementType)}>${nullable2}`;
45441
+ case "dictionary":
45442
+ return `d<${identity(type2.keyType)},${identity(type2.valueType)}>${nullable2}`;
45443
+ case "reference":
45444
+ return `r<${identity(type2.target)}>${nullable2}`;
45445
+ case "delegate":
45446
+ return `f<${identity(type2.returnType)};${type2.parameterTypes.map(identity).join(",")}>${nullable2}`;
45447
+ case "action":
45448
+ return `a<${type2.parameterTypes.map(identity).join(",")}>${nullable2}`;
45449
+ }
45450
+ }
45451
+ var FunctionTypeInference = class {
45452
+ constructor(parameters, project) {
45453
+ this.parameters = parameters;
45454
+ this.project = project;
45455
+ parameters.forEach((parameter3, index) => {
45456
+ if (parameter3.type.kind === "typeParameter")
45457
+ this.slots.set(parameter3.type.id, index);
45458
+ });
45459
+ this.bounds = parameters.map(() => /* @__PURE__ */ new Map());
45460
+ }
45461
+ parameters;
45462
+ project;
45463
+ slots = /* @__PURE__ */ new Map();
45464
+ bounds;
45465
+ fixed = /* @__PURE__ */ new Map();
45466
+ bind(type2) {
45467
+ return substituteNeoScriptTypeParameters(
45468
+ type2,
45469
+ (parameter3) => this.fixed.get(parameter3.id),
45470
+ this.project
45471
+ );
45472
+ }
45473
+ unresolved(type2) {
45474
+ const result = /* @__PURE__ */ new Set();
45475
+ const visit = (value) => {
45476
+ if (value.kind === "typeParameter") {
45477
+ const index = this.slots.get(value.id);
45478
+ if (index !== void 0 && !this.fixed.has(value.id)) result.add(index);
45479
+ } else {
45480
+ for (const child of children2(value)) visit(child);
45481
+ }
45482
+ };
45483
+ visit(type2);
45484
+ return result;
45485
+ }
45486
+ get pending() {
45487
+ return this.parameters.flatMap(
45488
+ (parameter3, index) => this.fixed.has(
45489
+ parameter3.type.kind === "typeParameter" ? parameter3.type.id : ""
45490
+ ) ? [] : [index]
45491
+ );
45492
+ }
45493
+ hasBounds(index) {
45494
+ return (this.bounds[index]?.size ?? 0) > 0;
45495
+ }
45496
+ add(actual, pattern, kind = "lower") {
45497
+ if (actual.kind === "primitive" && (actual.name === "null" || actual.name === "unknown" || actual.name === "void"))
45498
+ return;
45499
+ if (pattern.kind === "typeParameter") {
45500
+ const index = this.slots.get(pattern.id);
45501
+ if (index === void 0 || this.fixed.has(pattern.id)) return;
45502
+ const type2 = argumentType(
45503
+ pattern.nullable === true ? { ...actual, nullable: false } : actual
45504
+ );
45505
+ this.bounds[index]?.set(`${kind}:${identity(type2)}`, { type: type2, kind });
45506
+ return;
45507
+ }
45508
+ if (pattern.kind === "named") {
45509
+ const source = actual.kind === "typeParameter" ? actual.constraint : actual;
45510
+ if (source?.kind !== "named") return;
45511
+ const construction = supertypeConstruction(
45512
+ source,
45513
+ pattern.typeId,
45514
+ this.project
45515
+ );
45516
+ pattern.typeArguments?.forEach((expected, index) => {
45517
+ const value = construction?.[index];
45518
+ if (value !== void 0) this.add(value, expected, "exact");
45519
+ });
45520
+ return;
45521
+ }
45522
+ if (pattern.kind === "list" && actual.kind === "list" || pattern.kind === "set" && actual.kind === "set") {
45523
+ this.add(actual.elementType, pattern.elementType, "exact");
45524
+ } else if (pattern.kind === "dictionary" && actual.kind === "dictionary") {
45525
+ this.add(actual.keyType, pattern.keyType, "exact");
45526
+ this.add(actual.valueType, pattern.valueType, "exact");
45527
+ } else if (pattern.kind === "delegate" && actual.kind === "delegate") {
45528
+ this.add(actual.returnType, pattern.returnType, kind);
45529
+ pattern.parameterTypes.forEach((expected, index) => {
45530
+ const value = actual.parameterTypes[index];
45531
+ if (value !== void 0) this.add(value, expected, "exact");
45532
+ });
45533
+ } else if (pattern.kind === "action" && actual.kind === "action") {
45534
+ pattern.parameterTypes.forEach((expected, index) => {
45535
+ const value = actual.parameterTypes[index];
45536
+ if (value !== void 0) this.add(value, expected, "exact");
45537
+ });
45538
+ } else if (pattern.kind === "reference" && actual.kind === "reference") {
45539
+ this.add(actual.target, pattern.target, "exact");
45540
+ }
45541
+ }
45542
+ fix(index) {
45543
+ const parameter3 = this.parameters[index];
45544
+ if (parameter3?.type.kind !== "typeParameter")
45545
+ throw new Error("Missing function type parameter.");
45546
+ const bounds = [...this.bounds[index]?.values() ?? []];
45547
+ if (bounds.length === 0) {
45548
+ if (parameter3.type.defaultType === void 0)
45549
+ return `Cannot infer type argument '${parameter3.name}'; specify it explicitly.`;
45550
+ this.fixed.set(parameter3.type.id, parameter3.type.defaultType);
45551
+ return;
45552
+ }
45553
+ const exact = bounds.find((bound) => bound.kind === "exact");
45554
+ let candidate = exact?.type ?? bounds[0].type;
45555
+ if (!exact) {
45556
+ for (const bound of bounds)
45557
+ if (!isNeoScriptTypeAssignable(bound.type, candidate, this.project))
45558
+ candidate = bound.type;
45559
+ }
45560
+ const key = identity(candidate);
45561
+ const valid = bounds.every(
45562
+ (bound) => bound.kind === "exact" ? identity(bound.type) === key : isNeoScriptTypeAssignable(bound.type, candidate, this.project)
45563
+ );
45564
+ const ambiguous = !exact && bounds.some(
45565
+ (bound) => identity(bound.type) !== key && isNeoScriptTypeAssignable(candidate, bound.type, this.project)
45566
+ );
45567
+ if (!valid || ambiguous)
45568
+ return `Cannot infer type argument '${parameter3.name}' from conflicting types ${[...new Set(bounds.map((bound) => formatType(bound.type, this.project)))].join(", ")}; specify it explicitly.`;
45569
+ this.fixed.set(parameter3.type.id, candidate);
45570
+ }
45571
+ arguments() {
45572
+ return this.parameters.map((parameter3) => this.bind(parameter3.type));
45573
+ }
45574
+ };
45575
+ function children2(type2) {
45576
+ switch (type2.kind) {
45577
+ case "named":
45578
+ return type2.typeArguments ?? [];
45579
+ case "list":
45580
+ case "set":
45581
+ return [type2.elementType];
45582
+ case "dictionary":
45583
+ return [type2.keyType, type2.valueType];
45584
+ case "reference":
45585
+ return [type2.target];
45586
+ case "delegate":
45587
+ return [...type2.parameterTypes, type2.returnType];
45588
+ case "action":
45589
+ return type2.parameterTypes;
45590
+ default:
45591
+ return [];
45592
+ }
45593
+ }
45594
+ function argumentType(type2) {
45595
+ const optional2 = type2.nullable === true ? { nullable: true } : {};
45596
+ switch (type2.kind) {
45597
+ case "primitive":
45598
+ return { kind: type2.kind, name: type2.name, ...optional2 };
45599
+ case "typeParameter": {
45600
+ const declared = { ...type2 };
45601
+ delete declared.narrowedInterfaces;
45602
+ return declared;
45603
+ }
45604
+ case "named":
45605
+ return {
45606
+ kind: type2.kind,
45607
+ typeId: type2.typeId,
45608
+ ...type2.typeArguments ? { typeArguments: type2.typeArguments.map(argumentType) } : {},
45609
+ ...optional2
45610
+ };
45611
+ case "list":
45612
+ case "set":
45613
+ return {
45614
+ kind: type2.kind,
45615
+ elementType: argumentType(type2.elementType),
45616
+ ...optional2
45617
+ };
45618
+ case "dictionary":
45619
+ return {
45620
+ kind: type2.kind,
45621
+ keyType: argumentType(type2.keyType),
45622
+ valueType: argumentType(type2.valueType),
45623
+ ...optional2
45624
+ };
45625
+ case "reference":
45626
+ return {
45627
+ kind: type2.kind,
45628
+ target: argumentType(type2.target),
45629
+ ...optional2
45630
+ };
45631
+ case "delegate":
45632
+ return {
45633
+ kind: type2.kind,
45634
+ returnType: argumentType(type2.returnType),
45635
+ parameterTypes: type2.parameterTypes.map(argumentType),
45636
+ ...optional2
45637
+ };
45638
+ case "action":
45639
+ return {
45640
+ kind: type2.kind,
45641
+ parameterTypes: type2.parameterTypes.map(argumentType),
45642
+ ...optional2
45643
+ };
45644
+ }
45645
+ }
45646
+ function sameInferredType(left, right) {
45647
+ return identity(left) === identity(right);
45648
+ }
45649
+
44853
45650
  // ../packages/neoscript-language/src/source-map.ts
44854
45651
  function sourcePositionMapper(source) {
44855
45652
  if (!source?.mapping) return (position) => position;
@@ -45809,6 +46606,7 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
45809
46606
  debugPosition;
45810
46607
  unreachableControlEffectDepth = 0;
45811
46608
  catchBindingCounter = 0;
46609
+ switchExpressionCounter = 0;
45812
46610
  catchContexts = [];
45813
46611
  expectedReturnStack = [];
45814
46612
  controlContexts = [];
@@ -46896,6 +47694,17 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
46896
47694
  const inference = this.lambdaReturnInference.at(-1);
46897
47695
  const inferring = inference?.depth === this.lambdaDepth;
46898
47696
  const inferExpression = this.options.inferExpressionReturnType && this.lambdaDepth === 0;
47697
+ if (inferring && inference.contextualReturns && !hasIndependentTypeEvidence(statement.expr)) {
47698
+ inference.contextualReturns.push(statement.expr);
47699
+ return {
47700
+ type: "return" /* Return */,
47701
+ pointer: literal(
47702
+ { kind: "primitive", name: "unknown" },
47703
+ null,
47704
+ this.project
47705
+ ).pointer
47706
+ };
47707
+ }
46899
47708
  const value = this.resolveExpression(
46900
47709
  statement.expr,
46901
47710
  scope,
@@ -47461,12 +48270,9 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
47461
48270
  );
47462
48271
  }
47463
48272
  const bindings = [];
47464
- const capturedTarget = statement.op !== "=" && vectorTypeName(target.type) !== null ? {
48273
+ const capturedTarget = statement.op !== "=" && (vectorTypeName(target.type) !== null || isBitwiseBinaryOperator(statement.op.slice(0, -1))) ? {
47465
48274
  ...target,
47466
- pointer: this.captureVectorAssignmentTarget(
47467
- target.pointer,
47468
- bindings
47469
- )
48275
+ pointer: this.captureAssignmentTarget(target.pointer, bindings)
47470
48276
  } : target;
47471
48277
  let value;
47472
48278
  if (reference?.value !== void 0) {
@@ -47550,7 +48356,7 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
47550
48356
  pointer: value.pointer
47551
48357
  };
47552
48358
  }
47553
- captureVectorAssignmentTarget(pointer, bindings) {
48359
+ captureAssignmentTarget(pointer, bindings) {
47554
48360
  const capture = (value) => {
47555
48361
  if (value.type === "value" /* Value */) return value;
47556
48362
  const id = `$assignment_${this.assignmentBindingCounter++}`;
@@ -47639,6 +48445,14 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
47639
48445
  return { target: layer, value: valueAt(layer.type), through };
47640
48446
  }
47641
48447
  resolveReferenceAssignmentValue(expression, scope, storageType) {
48448
+ if (expression.kind === "switchExpression") {
48449
+ return this.resolveSwitchExpression(
48450
+ expression,
48451
+ scope,
48452
+ void 0,
48453
+ storageType
48454
+ );
48455
+ }
47642
48456
  if (expression.kind === "conditional") {
47643
48457
  return this.resolveConditionalExpression(
47644
48458
  expression,
@@ -47834,7 +48648,7 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
47834
48648
  ).type;
47835
48649
  }
47836
48650
  resolveCompoundAssignment(operation, valueAst, target, scope, pos) {
47837
- const binaryOperation = operation === "++" ? "+" : operation === "--" ? "-" : operation.slice(0, 1);
48651
+ const binaryOperation = operation === "++" ? "+" : operation === "--" ? "-" : operation.slice(0, -1);
47838
48652
  const right = operation === "++" || operation === "--" ? literal({ kind: "primitive", name: "int" }, 1) : valueAst ? this.resolveExpression(valueAst, scope, target.type) : null;
47839
48653
  if (!right) {
47840
48654
  throw new CompileError(
@@ -48773,6 +49587,10 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
48773
49587
  );
48774
49588
  return this.booleanComparison("==", bool, falseValue, expression.pos);
48775
49589
  }
49590
+ if (expression.op === "~") {
49591
+ this.requireBitwiseInt(operand, expression.pos);
49592
+ return bitwiseIntrinsic("not", [operand.pointer]);
49593
+ }
48776
49594
  const operandVector = vectorTypeName(operand.type);
48777
49595
  if (operandVector !== null && !isNullable(operand.type)) {
48778
49596
  return vectorIntrinsic(
@@ -48812,6 +49630,8 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
48812
49630
  }
48813
49631
  case "coalesce":
48814
49632
  return this.resolveCoalesceExpression(expression, scope, expected);
49633
+ case "switchExpression":
49634
+ return this.resolveSwitchExpression(expression, scope, expected);
48815
49635
  case "conditional":
48816
49636
  return this.resolveConditionalExpression(expression, scope, expected);
48817
49637
  case "is": {
@@ -48862,7 +49682,7 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
48862
49682
  );
48863
49683
  }
48864
49684
  }
48865
- resolveDelegateLambda(ast, expected, outerScope) {
49685
+ resolveDelegateLambda(ast, expected, outerScope, inferReturn = false) {
48866
49686
  if (ast.params.length !== expected.parameterTypes.length) {
48867
49687
  throw new CompileError(
48868
49688
  `Delegate lambda expects ${expected.parameterTypes.length} parameter${expected.parameterTypes.length === 1 ? "" : "s"}, got ${ast.params.length}.`,
@@ -48916,6 +49736,12 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
48916
49736
  "runtime" /* Runtime */
48917
49737
  )
48918
49738
  );
49739
+ this.options.onFlowScope?.({
49740
+ name: parameter3.name,
49741
+ position: parameter3.pos,
49742
+ type: declared,
49743
+ bindings: scope.patternBindings
49744
+ });
48919
49745
  return item;
48920
49746
  });
48921
49747
  const captureContext = {
@@ -48933,6 +49759,12 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
48933
49759
  });
48934
49760
  this.lambdaDepth++;
48935
49761
  this.expectedReturnStack.push(expected.returnType);
49762
+ const inference = {
49763
+ depth: this.lambdaDepth,
49764
+ contextualReturns: [],
49765
+ returns: []
49766
+ };
49767
+ if (inferReturn) this.lambdaReturnInference.push(inference);
48936
49768
  try {
48937
49769
  const returnsVoid = isVoid(expected.returnType);
48938
49770
  const instructions = this.resolveStatements(
@@ -48945,6 +49777,26 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
48945
49777
  ast.pos
48946
49778
  );
48947
49779
  }
49780
+ if (inferReturn) {
49781
+ let inferred;
49782
+ for (const returned of inference.returns) {
49783
+ const joined = inferred === void 0 ? returned.value.type : commonNeoScriptAssignableType(
49784
+ inferred,
49785
+ returned.value.type,
49786
+ this.project
49787
+ );
49788
+ if (joined === null)
49789
+ throw new CompileError(
49790
+ "Lambda returns incompatible types for function type inference.",
49791
+ returned.pos
49792
+ );
49793
+ inferred = joined;
49794
+ }
49795
+ expected = {
49796
+ ...expected,
49797
+ returnType: inferred ?? { kind: "primitive", name: "unknown" }
49798
+ };
49799
+ }
48948
49800
  const action = {
48949
49801
  compilerRevision: NEOSCRIPT_COMPILER_REVISION,
48950
49802
  source: {
@@ -48977,19 +49829,24 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
48977
49829
  captures: captureContext.captures.map((capture) => capture.source),
48978
49830
  ...code === void 0 ? {} : { code }
48979
49831
  },
48980
- type: expected
49832
+ type: expected,
49833
+ needsReturnContext: inference.contextualReturns.length > 0
48981
49834
  };
48982
49835
  }
48983
- return literal(
48984
- expected,
48985
- code === void 0 ? { action } : { code, action },
48986
- this.project
48987
- );
49836
+ return {
49837
+ ...literal(
49838
+ expected,
49839
+ code === void 0 ? { action } : { code, action },
49840
+ this.project
49841
+ ),
49842
+ needsReturnContext: inference.contextualReturns.length > 0
49843
+ };
48988
49844
  } finally {
48989
49845
  this.expectedReturnStack.pop();
48990
49846
  this.lambdaDepth--;
48991
49847
  this.functionControlBoundaries.pop();
48992
49848
  this.delegateCaptureContexts.pop();
49849
+ if (inferReturn) this.lambdaReturnInference.pop();
48993
49850
  }
48994
49851
  }
48995
49852
  delegateLambdaSource(ast) {
@@ -49143,7 +50000,9 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
49143
50000
  );
49144
50001
  }
49145
50002
  /** Derives the exact expected delegate signature for a test mock target. */
49146
- inferDelegateMethodGroupType(expression, scope) {
50003
+ inferDelegateMethodGroupType(expression, scope, mockTarget = true) {
50004
+ if (expression.kind === "ident" && scope.lookup(expression.name))
50005
+ return null;
49147
50006
  let symbol;
49148
50007
  let owner;
49149
50008
  let receiverType;
@@ -49181,7 +50040,7 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
49181
50040
  }
49182
50041
  const mockArguments = methodGroupTypeArguments(
49183
50042
  symbol,
49184
- true,
50043
+ mockTarget,
49185
50044
  expression.pos
49186
50045
  );
49187
50046
  const receiver = callReceiver(receiverType, owner);
@@ -49216,6 +50075,8 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
49216
50075
  };
49217
50076
  });
49218
50077
  if (pointers.length === 0) return literal(stringType, "");
50078
+ if (parts[0]?.kind !== "lit")
50079
+ pointers.unshift(literal(stringType, "").pointer);
49219
50080
  return {
49220
50081
  pointer: {
49221
50082
  type: "operation" /* Operation */,
@@ -52507,12 +53368,33 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
52507
53368
  * cases are unreachable unless the host injected the test prelude.
52508
53369
  */
52509
53370
  resolveCallableArguments(symbol, receiver, argumentsList2, scope, pos, typeArguments) {
53371
+ const inferred = typeArguments === void 0 && symbol.typeParameters?.length ? this.inferFunctionTypeArguments(
53372
+ symbol,
53373
+ receiver,
53374
+ argumentsList2,
53375
+ scope,
53376
+ pos
53377
+ ) : void 0;
52510
53378
  const signature = this.callableSignatureForReceiver(
52511
53379
  symbol,
52512
53380
  receiver,
52513
53381
  typeArguments,
52514
- pos
52515
- );
53382
+ pos,
53383
+ inferred?.typeArguments
53384
+ );
53385
+ if (signature.typeArguments.length > 0)
53386
+ this.options.onCallResolved?.(pos, {
53387
+ ...symbol,
53388
+ type: signature.returnType,
53389
+ returnType: signature.returnType,
53390
+ parameters: signature.parameters,
53391
+ typeParameters: (symbol.typeParameters ?? []).map(
53392
+ (parameter3, index) => ({
53393
+ ...parameter3,
53394
+ type: requiredAt(signature.typeArguments, index)
53395
+ })
53396
+ )
53397
+ });
52516
53398
  const wireTypeArguments = signature.typeArguments.length ? {
52517
53399
  typeArguments: signature.typeArguments.map(
52518
53400
  (argument2) => toWireType(argument2, this.project)
@@ -52719,7 +53601,8 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
52719
53601
  receiver.expression.type
52720
53602
  ) ?? expected;
52721
53603
  }
52722
- const resolved = isUnknown(expected) ? this.resolveExpression(argument2, scope) : this.resolveExpression(argument2, scope, expected);
53604
+ const cached = inferred?.resolved.get(argument2);
53605
+ const resolved = cached && (sameInferredType(cached.type, expected) || cached.pointer.type === "callFunction" /* CallFunction */) ? cached : isUnknown(expected) ? this.resolveExpression(argument2, scope) : this.resolveExpression(argument2, scope, expected);
52723
53606
  if (!isUnknown(expected)) {
52724
53607
  this.requireReferenceArgument(
52725
53608
  resolved.type,
@@ -52749,13 +53632,134 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
52749
53632
  }
52750
53633
  return { args, returnType: signature.returnType, ...wireTypeArguments };
52751
53634
  }
52752
- callableSignatureForReceiver(symbol, receiver, typeArguments, pos) {
53635
+ inferFunctionTypeArguments(symbol, receiver, argumentsList2, scope, pos) {
53636
+ const inference = new FunctionTypeInference(
53637
+ symbol.typeParameters ?? [],
53638
+ this.project
53639
+ );
53640
+ const bound = this.genericCallReceiver(receiver);
53641
+ const parameters = (symbol.parameters ?? []).map(
53642
+ (parameter3) => substituteCallTypeArguments(
53643
+ parameter3.type,
53644
+ [],
53645
+ void 0,
53646
+ bound,
53647
+ this.project
53648
+ )
53649
+ );
53650
+ const callbacks = [];
53651
+ const probe = new Scope(scope);
53652
+ const resolvedArguments = /* @__PURE__ */ new Map();
53653
+ argumentsList2.forEach((argument2, index) => {
53654
+ const pattern = parameters[index];
53655
+ if (pattern === void 0) return;
53656
+ if (inference.unresolved(pattern).size === 0) return;
53657
+ if (argument2.kind === "lambda" && pattern.kind === "delegate") {
53658
+ argument2.params.forEach((parameter3, parameterIndex) => {
53659
+ const expected = pattern.parameterTypes[parameterIndex];
53660
+ if (parameter3.type && expected)
53661
+ inference.add(this.resolveType(parameter3.type), expected, "exact");
53662
+ });
53663
+ callbacks.push({ ast: argument2, type: pattern });
53664
+ return;
53665
+ }
53666
+ if (!hasIndependentTypeEvidence(argument2)) return;
53667
+ const method2 = pattern.kind === "delegate" ? this.inferDelegateMethodGroupType(argument2, probe, false) : null;
53668
+ if (method2 !== null) inference.add(method2, pattern);
53669
+ else {
53670
+ const resolved = this.resolveExpression(argument2, probe);
53671
+ resolvedArguments.set(argument2, resolved);
53672
+ inference.add(resolved.type, pattern);
53673
+ }
53674
+ });
53675
+ while (inference.pending.length > 0) {
53676
+ for (let index = callbacks.length - 1; index >= 0; index--) {
53677
+ const callback = callbacks[index];
53678
+ if (callback.type.parameterTypes.some(
53679
+ (type2) => inference.unresolved(type2).size > 0
53680
+ ))
53681
+ continue;
53682
+ if (inference.unresolved(callback.type.returnType).size === 0) {
53683
+ callbacks.splice(index, 1);
53684
+ continue;
53685
+ }
53686
+ const inputs = callback.type.parameterTypes.map(
53687
+ (type2) => inference.bind(type2)
53688
+ );
53689
+ const resolved = this.resolveDelegateLambda(
53690
+ callback.ast,
53691
+ {
53692
+ kind: "delegate",
53693
+ parameterTypes: inputs,
53694
+ returnType: { kind: "primitive", name: "unknown" }
53695
+ },
53696
+ probe,
53697
+ true
53698
+ );
53699
+ if (resolved.type.kind === "delegate")
53700
+ inference.add(resolved.type.returnType, callback.type.returnType);
53701
+ if (!resolved.needsReturnContext)
53702
+ resolvedArguments.set(callback.ast, resolved);
53703
+ callbacks.splice(index, 1);
53704
+ }
53705
+ const dependencies = /* @__PURE__ */ new Map();
53706
+ const producers = /* @__PURE__ */ new Set();
53707
+ for (const callback of callbacks) {
53708
+ const inputs = new Set(
53709
+ callback.type.parameterTypes.flatMap((type2) => [
53710
+ ...inference.unresolved(type2)
53711
+ ])
53712
+ );
53713
+ for (const output of inference.unresolved(callback.type.returnType)) {
53714
+ producers.add(output);
53715
+ const entry = dependencies.get(output) ?? /* @__PURE__ */ new Set();
53716
+ for (const input of inputs) entry.add(input);
53717
+ dependencies.set(output, entry);
53718
+ }
53719
+ }
53720
+ const pending = inference.pending;
53721
+ let fix = pending.filter(
53722
+ (index) => inference.hasBounds(index) && !dependencies.get(index)?.size
53723
+ );
53724
+ if (fix.length === 0) {
53725
+ const dependedOn = new Set(
53726
+ [...dependencies.values()].flatMap((entry) => [...entry])
53727
+ );
53728
+ fix = pending.filter(
53729
+ (index) => inference.hasBounds(index) && dependedOn.has(index)
53730
+ );
53731
+ }
53732
+ if (fix.length === 0)
53733
+ fix = pending.filter((index) => {
53734
+ const type2 = inference.parameters[index]?.type;
53735
+ return !inference.hasBounds(index) && !producers.has(index) && type2?.kind === "typeParameter" && type2.defaultType !== void 0;
53736
+ });
53737
+ if (fix.length === 0) {
53738
+ const names = pending.map((index) => `'${inference.parameters[index]?.name}'`).join(", ");
53739
+ throw new CompileError(
53740
+ `Cannot infer type argument ${names} for '${symbol.name}'; specify it explicitly.`,
53741
+ pos
53742
+ );
53743
+ }
53744
+ for (const index of fix) {
53745
+ const error = inference.fix(index);
53746
+ if (error)
53747
+ throw new CompileError(`${error} Function '${symbol.name}'.`, pos);
53748
+ }
53749
+ }
53750
+ return {
53751
+ typeArguments: inference.arguments(),
53752
+ resolved: resolvedArguments
53753
+ };
53754
+ }
53755
+ callableSignatureForReceiver(symbol, receiver, typeArguments, pos, inferred) {
52753
53756
  const bound = this.genericCallReceiver(receiver);
52754
53757
  const functionArguments = this.resolveFunctionTypeArguments(
52755
53758
  symbol,
52756
53759
  typeArguments,
52757
53760
  (type2) => substituteCallTypeArguments(type2, [], void 0, bound, this.project),
52758
- pos
53761
+ pos,
53762
+ inferred
52759
53763
  );
52760
53764
  const bind = (type2) => substituteCallTypeArguments(
52761
53765
  type2,
@@ -52789,7 +53793,7 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
52789
53793
  * arguments, then defaults. Each written argument is non-nullable and
52790
53794
  * satisfies its param's constraint.
52791
53795
  */
52792
- resolveFunctionTypeArguments(symbol, typeArguments, substitute, pos) {
53796
+ resolveFunctionTypeArguments(symbol, typeArguments, substitute, pos, inferred) {
52793
53797
  const parameters = symbol.typeParameters ?? [];
52794
53798
  if (parameters.length === 0) {
52795
53799
  if (typeArguments === void 0) return [];
@@ -52813,31 +53817,32 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
52813
53817
  );
52814
53818
  }
52815
53819
  const authored = written[index];
52816
- if (authored === void 0) {
53820
+ if (authored === void 0 && inferred?.[index] === void 0) {
52817
53821
  if (declared.defaultType !== void 0) return declared.defaultType;
52818
53822
  throw new CompileError(
52819
53823
  `'${symbol.name}' needs a type argument for '${parameter3.name}'.`,
52820
53824
  pos
52821
53825
  );
52822
53826
  }
52823
- const argument2 = this.resolveType(authored);
53827
+ const argument2 = authored === void 0 ? requiredAt(inferred ?? [], index) : this.resolveType(authored);
53828
+ const argumentPosition = authored?.pos ?? pos;
52824
53829
  if (argument2.nullable === true) {
52825
53830
  throw new CompileError(
52826
53831
  `Type argument '${this.describe(argument2)}' cannot be nullable; declare '${parameter3.name}?' in the signature instead.`,
52827
- authored.pos
53832
+ argumentPosition
52828
53833
  );
52829
53834
  }
52830
53835
  if (symbol.native === true && !symbol.id.startsWith(SYSTEM_RECORD_ID_PREFIX2) && argument2.kind === "named" && (argument2.typeArguments?.length ?? 0) > 0) {
52831
53836
  throw new CompileError(
52832
53837
  `Native function '${symbol.name}' takes a non-generic class type argument; '${this.describe(argument2)}' is generic.`,
52833
- authored.pos
53838
+ argumentPosition
52834
53839
  );
52835
53840
  }
52836
53841
  const constraint = declared.constraint === void 0 ? void 0 : substitute(declared.constraint);
52837
53842
  if (constraint !== void 0 && !isNeoScriptTypeAssignable(argument2, constraint, this.project)) {
52838
53843
  throw new CompileError(
52839
53844
  `Type argument '${this.describe(argument2)}' does not satisfy '${parameter3.name} extends ${this.describe(constraint)}' on '${symbol.name}'.`,
52840
- authored.pos
53845
+ argumentPosition
52841
53846
  );
52842
53847
  }
52843
53848
  return argument2;
@@ -54754,6 +55759,210 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
54754
55759
  type: resultType
54755
55760
  };
54756
55761
  }
55762
+ resolveSwitchExpression(expression, scope, expected, assignmentType) {
55763
+ const selector = this.resolveExpression(expression.selector, scope);
55764
+ const selectorId = `__switch:${this.switchExpressionCounter++}`;
55765
+ if (expression.arms.length === 0)
55766
+ throw new CompileError(
55767
+ "A switch expression needs at least one arm.",
55768
+ expression.pos
55769
+ );
55770
+ const coverage = new SwitchCoverage(this.project);
55771
+ const arms = [];
55772
+ for (let index = 0; index < expression.arms.length; index++) {
55773
+ const source = expression.arms[index];
55774
+ const armScope = new Scope(scope);
55775
+ let pattern;
55776
+ let covered;
55777
+ if (source.pattern.kind === "discard") {
55778
+ pattern = { kind: "discard" };
55779
+ covered = pattern;
55780
+ } else if (source.pattern.kind === "constant") {
55781
+ const constant = this.resolveSwitchCaseLabel(
55782
+ source.pattern.expression,
55783
+ selector.type,
55784
+ scope
55785
+ );
55786
+ pattern = { kind: "constant", constant };
55787
+ covered = {
55788
+ kind: "constant",
55789
+ value: Array.isArray(constant.value) ? constant.value[0] : constant.value
55790
+ };
55791
+ } else {
55792
+ const check2 = this.resolveType(source.pattern.type);
55793
+ if (isNullable(check2))
55794
+ throw new CompileError(
55795
+ "A switch type pattern must be non-nullable; use a null arm separately.",
55796
+ source.pos
55797
+ );
55798
+ if (!typesOverlap(selector.type, check2, this.project))
55799
+ throw new CompileError(
55800
+ `Pattern ${this.describe(check2)} cannot match ${this.describe(selector.type)}.`,
55801
+ source.pos
55802
+ );
55803
+ const bindingId = `${selectorId}_arm_${index}`;
55804
+ pattern = { kind: "type", checkType: toWireType(check2, this.project) };
55805
+ covered = { kind: "type", type: check2 };
55806
+ if (source.pattern.bindingName) {
55807
+ this.assertLocalNameAvailable(
55808
+ source.pattern.bindingName,
55809
+ scope,
55810
+ source.pos
55811
+ );
55812
+ pattern = { ...pattern, bindingId };
55813
+ armScope.definePattern({
55814
+ name: source.pattern.bindingName,
55815
+ type: check2,
55816
+ variableId: bindingId,
55817
+ pointer: {
55818
+ type: "variable" /* Variable */,
55819
+ variableId: bindingId
55820
+ },
55821
+ ...selector.writability ? { writability: selector.writability } : {},
55822
+ ...selector.writeRoot ? { writeRoot: selector.writeRoot } : {}
55823
+ });
55824
+ }
55825
+ }
55826
+ if (coverage.subsumes(covered, selector.type))
55827
+ throw new CompileError(
55828
+ "This switch arm is already covered by earlier arms.",
55829
+ source.pos
55830
+ );
55831
+ if (source.guard?.kind === "litBool" && !source.guard.value)
55832
+ throw new CompileError(
55833
+ "A switch arm with a false guard is unreachable.",
55834
+ source.guard.pos
55835
+ );
55836
+ const guard = source.guard ? this.resolveExpression(source.guard, armScope) : void 0;
55837
+ if (guard)
55838
+ this.requireAssignable(
55839
+ guard.type,
55840
+ { kind: "primitive", name: "bool" },
55841
+ source.guard.pos,
55842
+ "switch guard"
55843
+ );
55844
+ if (source.guard)
55845
+ this.applyFactsToScope(
55846
+ armScope,
55847
+ this.conditionFacts(source.guard, armScope, true)
55848
+ );
55849
+ arms.push({
55850
+ source,
55851
+ scope: armScope,
55852
+ pattern,
55853
+ ...guard ? { guard: guard.pointer } : {}
55854
+ });
55855
+ if (!source.guard || source.guard.kind === "litBool" && source.guard.value)
55856
+ coverage.add(covered);
55857
+ }
55858
+ const missing = missingSwitchCases(selector.type, coverage, this.project);
55859
+ if (missing.length)
55860
+ throw new CompileError(
55861
+ `Switch expression over ${this.describe(selector.type)} is not exhaustive. Missing: ${missing.join(", ")}.`,
55862
+ expression.pos
55863
+ );
55864
+ let assignmentResults;
55865
+ if (assignmentType) {
55866
+ assignmentResults = arms.map(
55867
+ (arm) => this.resolveReferenceAssignmentValue(
55868
+ arm.source.value,
55869
+ arm.scope,
55870
+ assignmentType
55871
+ )
55872
+ );
55873
+ let common = assignmentResults[0].type;
55874
+ for (const value of assignmentResults.slice(1)) {
55875
+ if (!common) break;
55876
+ if (isNull(value.type)) common = { ...common, nullable: true };
55877
+ else if (isNull(common)) common = { ...value.type, nullable: true };
55878
+ else
55879
+ common = commonNeoScriptAssignableType(
55880
+ common,
55881
+ value.type,
55882
+ this.project
55883
+ );
55884
+ }
55885
+ if (common) expected = common;
55886
+ else {
55887
+ let layer = assignmentType;
55888
+ while (true) {
55889
+ const atLayer = assignmentResults.map(
55890
+ (value) => this.readReferences(value, layer)
55891
+ );
55892
+ if (atLayer.every(
55893
+ (value) => isNeoScriptTypeAssignable(value.type, layer, this.project)
55894
+ )) {
55895
+ assignmentResults = atLayer;
55896
+ expected = layer;
55897
+ break;
55898
+ }
55899
+ if (layer.kind !== "reference") {
55900
+ expected = layer;
55901
+ break;
55902
+ }
55903
+ layer = layer.target;
55904
+ }
55905
+ }
55906
+ }
55907
+ let resultType = expected;
55908
+ const inferredResults = /* @__PURE__ */ new Map();
55909
+ if (!resultType) {
55910
+ for (const arm of arms) {
55911
+ if (!hasIndependentTypeEvidence(arm.source.value)) continue;
55912
+ const resolved = this.resolveExpression(arm.source.value, arm.scope);
55913
+ inferredResults.set(arm.source.value, resolved);
55914
+ const common = resultType ? commonNeoScriptAssignableType(
55915
+ resultType,
55916
+ resolved.type,
55917
+ this.project
55918
+ ) : resolved.type;
55919
+ if (!common)
55920
+ throw new CompileError(
55921
+ "Switch results have no common assignable type; specify a target type.",
55922
+ arm.source.value.pos
55923
+ );
55924
+ resultType = common;
55925
+ }
55926
+ if (resultType && arms.some(
55927
+ (arm) => !inferredResults.has(arm.source.value) && hasNullResult(arm.source.value)
55928
+ ))
55929
+ resultType = { ...resultType, nullable: true };
55930
+ }
55931
+ if (!resultType)
55932
+ throw new CompileError(
55933
+ "Cannot infer switch result type; specify a target type.",
55934
+ expression.pos
55935
+ );
55936
+ if (resultType.kind === "primitive" && resultType.name === "void")
55937
+ throw new CompileError(
55938
+ "A switch expression cannot return void.",
55939
+ expression.pos
55940
+ );
55941
+ const compiled = arms.map((arm, index) => {
55942
+ const value = assignmentResults?.[index] ?? inferredResults.get(arm.source.value) ?? this.resolveExpression(arm.source.value, arm.scope, resultType);
55943
+ this.requireAssignable(
55944
+ value.type,
55945
+ resultType,
55946
+ arm.source.value.pos,
55947
+ "switch result"
55948
+ );
55949
+ return {
55950
+ pattern: arm.pattern,
55951
+ ...arm.guard ? { guard: arm.guard } : {},
55952
+ value: value.pointer
55953
+ };
55954
+ });
55955
+ return {
55956
+ pointer: {
55957
+ type: "switchExpression" /* SwitchExpression */,
55958
+ selectorTypeInfo: toWireType(selector.type, this.project),
55959
+ selector: selector.pointer,
55960
+ selectorId,
55961
+ arms: compiled
55962
+ },
55963
+ type: resultType
55964
+ };
55965
+ }
54757
55966
  resolveConditionalExpression(expression, scope, expected, assignmentType) {
54758
55967
  const condition = this.toBool(
54759
55968
  this.resolveExpression(expression.condition, scope),
@@ -54916,6 +56125,18 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
54916
56125
  }
54917
56126
  return this.resolveBinaryValues(expression.op, left, right, expression.pos);
54918
56127
  }
56128
+ requireBitwiseInt(value, pos) {
56129
+ if (!isPrimitive(value.type, "int"))
56130
+ throw new CompileError(
56131
+ `Bitwise operators require int operands; got ${this.describe(value.type)}.`,
56132
+ pos
56133
+ );
56134
+ if (isNullable(value.type))
56135
+ throw new CompileError(
56136
+ "Bitwise operators require non-optional int operands.",
56137
+ pos
56138
+ );
56139
+ }
54919
56140
  resolveBinaryValues(operator, left, right, pos) {
54920
56141
  if (isNullable(left.type) || isNullable(right.type)) {
54921
56142
  throw new CompileError(
@@ -54923,6 +56144,14 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
54923
56144
  pos
54924
56145
  );
54925
56146
  }
56147
+ if (isBitwiseBinaryOperator(operator)) {
56148
+ this.requireBitwiseInt(left, pos);
56149
+ this.requireBitwiseInt(right, pos);
56150
+ return bitwiseIntrinsic(BITWISE_BINARY_OPERATORS[operator], [
56151
+ left.pointer,
56152
+ right.pointer
56153
+ ]);
56154
+ }
54926
56155
  let result;
54927
56156
  if (operator === "+" && (isPrimitive(left.type, "string") || isPrimitive(right.type, "string"))) {
54928
56157
  result = { kind: "primitive", name: "string" };
@@ -56266,6 +57495,19 @@ function collectAssignedPathsInExpression(expression, roots, locals, flowCache)
56266
57495
  flowCache
56267
57496
  );
56268
57497
  return;
57498
+ case "switchExpression":
57499
+ collectAssignedPathsInExpression(
57500
+ expression.selector,
57501
+ roots,
57502
+ locals,
57503
+ flowCache
57504
+ );
57505
+ for (const arm of expression.arms) {
57506
+ if (arm.guard)
57507
+ collectAssignedPathsInExpression(arm.guard, roots, locals, flowCache);
57508
+ collectAssignedPathsInExpression(arm.value, roots, locals, flowCache);
57509
+ }
57510
+ return;
56269
57511
  case "conditional":
56270
57512
  collectAssignedPathsInExpression(
56271
57513
  expression.condition,
@@ -56982,6 +58224,12 @@ function comparisonOperator(operator) {
56982
58224
  }
56983
58225
  function assignmentOperator(operator) {
56984
58226
  switch (operator) {
58227
+ case "&=":
58228
+ case "|=":
58229
+ case "^=":
58230
+ case "<<=":
58231
+ case ">>=":
58232
+ case ">>>=":
56985
58233
  case "=":
56986
58234
  return "=" /* Assign */;
56987
58235
  case "+=":
@@ -57493,6 +58741,71 @@ function callReceiver(receiverType, declaring) {
57493
58741
  if (declaring === void 0) return void 0;
57494
58742
  return { type: receiverType, declaring };
57495
58743
  }
58744
+ function hasNullResult(expression) {
58745
+ switch (expression.kind) {
58746
+ case "litNull":
58747
+ return true;
58748
+ case "conditional":
58749
+ return hasNullResult(expression.whenTrue) || hasNullResult(expression.whenFalse);
58750
+ case "switchExpression":
58751
+ return expression.arms.some((arm) => hasNullResult(arm.value));
58752
+ case "coalesce":
58753
+ return hasNullResult(expression.right);
58754
+ default:
58755
+ return false;
58756
+ }
58757
+ }
58758
+ function hasIndependentTypeEvidence(expression) {
58759
+ switch (expression.kind) {
58760
+ case "litNull":
58761
+ case "contextualEnum":
58762
+ case "lambda":
58763
+ return false;
58764
+ case "new":
58765
+ return expression.className !== null;
58766
+ case "conditional":
58767
+ return hasIndependentTypeEvidence(
58768
+ expression.whenTrue.kind === "litNull" || expression.whenTrue.kind === "contextualEnum" ? expression.whenFalse : expression.whenTrue
58769
+ );
58770
+ case "coalesce":
58771
+ return hasIndependentTypeEvidence(
58772
+ expression.left.kind === "litNull" ? expression.right : expression.left
58773
+ );
58774
+ case "switchExpression":
58775
+ return expression.arms.some(
58776
+ (arm) => hasIndependentTypeEvidence(arm.value)
58777
+ );
58778
+ case "litList":
58779
+ return independentlyTypedElements(expression.elements);
58780
+ case "litDict":
58781
+ return independentlyTypedElements(
58782
+ expression.entries.flatMap((entry) => [entry.key, entry.value])
58783
+ );
58784
+ default:
58785
+ return true;
58786
+ }
58787
+ }
58788
+ function independentlyTypedElements(expressions) {
58789
+ let hasEvidence = false;
58790
+ for (const expression of expressions) {
58791
+ if (expression.kind === "litNull") continue;
58792
+ if (!hasIndependentTypeEvidence(expression)) return false;
58793
+ hasEvidence = true;
58794
+ }
58795
+ return hasEvidence;
58796
+ }
58797
+ function bitwiseIntrinsic(op, argPointers) {
58798
+ return {
58799
+ pointer: {
58800
+ type: "function" /* Function */,
58801
+ function: {
58802
+ type: "bitwiseOp" /* BitwiseOp */,
58803
+ info: { op, argPointers }
58804
+ }
58805
+ },
58806
+ type: { kind: "primitive", name: "int" }
58807
+ };
58808
+ }
57496
58809
 
57497
58810
  // ../packages/neoscript-language/src/map-ir.ts
57498
58811
  function mapNeoScriptIR(root, visitor) {
@@ -57586,6 +58899,7 @@ function compileNeoScriptStrict(document2, context, options = {}) {
57586
58899
  {
57587
58900
  source: options.source,
57588
58901
  onFlowScope: options.onFlowScope,
58902
+ onCallResolved: options.onCallResolved,
57589
58903
  sourceUri: document2.uri,
57590
58904
  inferExpressionReturnType: options.inferExpressionReturnType
57591
58905
  }
@@ -57661,7 +58975,8 @@ function compileUnit(syntax, unit, context, label, projectIndex, options = {}) {
57661
58975
  return attachDependencyManifest(
57662
58976
  new StrictNeoScriptResolver(context, indexedProject, syntax, {
57663
58977
  source: options.source,
57664
- onFlowScope: options.onFlowScope
58978
+ onFlowScope: options.onFlowScope,
58979
+ onCallResolved: options.onCallResolved
57665
58980
  }).compile(ast),
57666
58981
  syntax,
57667
58982
  indexedProject,
@@ -58245,7 +59560,8 @@ function schemaClass(value, environment, field) {
58245
59560
  environment,
58246
59561
  field
58247
59562
  ),
58248
- ...value.declarationModifier === "abstract" ? { abstract: true } : {},
59563
+ ...value.declarationModifier === "abstract" || value.declarationModifier === "closed" ? { abstract: true } : {},
59564
+ ...value.declarationModifier === "closed" ? { closed: true } : {},
58249
59565
  ...value.declarationModifier === "sealed" ? { sealed: true } : {},
58250
59566
  ...allowedStorageField(resolvedAllowedStorage(id, environment)),
58251
59567
  ...sourceLocation(value.source, environment, `${field}.source`),
@@ -60426,6 +61742,7 @@ function classToLanguageType(schemaClass2, context) {
60426
61742
  ...schemaClass2.docsText ? { documentation: schemaClass2.docsText } : {},
60427
61743
  kind: "class",
60428
61744
  abstract: isAbstractClass(schemaClass2),
61745
+ closed: isClosedHierarchyClass(schemaClass2),
60429
61746
  ...allowedStorageField2(
60430
61747
  resolveAllowedStorage(schemaClass2.id, context.vm.classes)
60431
61748
  ),
@@ -62110,9 +63427,9 @@ function compileStrict(code, context, sourceInfo, inferExpressionReturnType = fa
62110
63427
  function compilationProjectIdentity(project) {
62111
63428
  const cached = neoScriptProjectIdentityCache.get(project);
62112
63429
  if (cached !== void 0) return cached;
62113
- const identity = nextNeoScriptProjectIdentity++;
62114
- neoScriptProjectIdentityCache.set(project, identity);
62115
- return identity;
63430
+ const identity2 = nextNeoScriptProjectIdentity++;
63431
+ neoScriptProjectIdentityCache.set(project, identity2);
63432
+ return identity2;
62116
63433
  }
62117
63434
  function compilationProjectIndex(project) {
62118
63435
  return cachedProjectIndex(project);
@@ -65669,7 +66986,8 @@ var COLUMN_OVERFLOW_KINDS = [
65669
66986
  var CLASS_MODIFIER_KINDS = [
65670
66987
  0 /* Open */,
65671
66988
  1 /* Abstract */,
65672
- 2 /* Sealed */
66989
+ 2 /* Sealed */,
66990
+ 3 /* Closed */
65673
66991
  ];
65674
66992
  var CLASS_VISIBILITY_KINDS = [
65675
66993
  0 /* Visible */,
@@ -66117,12 +67435,12 @@ function createGenerationContext(exportData, diagnostics, docs = EMPTY_UNITY_COD
66117
67435
  const dialogueGroupsByParent = /* @__PURE__ */ new Map();
66118
67436
  for (const group of dialogueGroups) {
66119
67437
  const parentId = group.parentDialogueGroupId ?? null;
66120
- let children = dialogueGroupsByParent.get(parentId);
66121
- if (children === void 0) {
66122
- children = [];
66123
- dialogueGroupsByParent.set(parentId, children);
67438
+ let children3 = dialogueGroupsByParent.get(parentId);
67439
+ if (children3 === void 0) {
67440
+ children3 = [];
67441
+ dialogueGroupsByParent.set(parentId, children3);
66124
67442
  }
66125
- children.push(group);
67443
+ children3.push(group);
66126
67444
  }
66127
67445
  const projectClassName = toCSharpTypeName(
66128
67446
  `${exportData.project.name}Neo`,
@@ -67211,28 +68529,28 @@ function csharpDelegateType(ctx, member, genericBindingSaved, genericEnv) {
67211
68529
  if (returnType === null) return null;
67212
68530
  const argumentTypes = [];
67213
68531
  for (const argument2 of member.argumentTypes) {
67214
- const argumentType = csharpFunctionTypeInfoValueType(
68532
+ const argumentType2 = csharpFunctionTypeInfoValueType(
67215
68533
  ctx,
67216
68534
  argument2,
67217
68535
  genericBindingSaved,
67218
68536
  genericEnv
67219
68537
  );
67220
- if (argumentType === null) return null;
67221
- argumentTypes.push(argumentType);
68538
+ if (argumentType2 === null) return null;
68539
+ argumentTypes.push(argumentType2);
67222
68540
  }
67223
68541
  return `NeoDelegate<${[returnType, ...argumentTypes].join(", ")}>`;
67224
68542
  }
67225
68543
  function csharpActionType(ctx, member, genericBindingSaved, genericEnv) {
67226
68544
  const argumentTypes = [];
67227
68545
  for (const argument2 of member.argumentTypes) {
67228
- const argumentType = csharpFunctionTypeInfoValueType(
68546
+ const argumentType2 = csharpFunctionTypeInfoValueType(
67229
68547
  ctx,
67230
68548
  argument2,
67231
68549
  genericBindingSaved,
67232
68550
  genericEnv
67233
68551
  );
67234
- if (argumentType === null) return null;
67235
- argumentTypes.push(argumentType);
68552
+ if (argumentType2 === null) return null;
68553
+ argumentTypes.push(argumentType2);
67236
68554
  }
67237
68555
  if (argumentTypes.length === 0) return "NeoAction";
67238
68556
  return `NeoAction<${argumentTypes.join(", ")}>`;
@@ -68284,6 +69602,36 @@ function pointerSource(ctx, pointer, variables, visitedGetterMemberIds) {
68284
69602
  variables,
68285
69603
  visitedGetterMemberIds
68286
69604
  );
69605
+ case "switchExpression" /* switchExpression */: {
69606
+ const selector = pointerSource(
69607
+ ctx,
69608
+ pointer.selector,
69609
+ variables,
69610
+ visitedGetterMemberIds
69611
+ );
69612
+ const sources2 = pointer.arms.map((arm) => {
69613
+ const armVariables = new Map(variables);
69614
+ armVariables.set(pointer.selectorId, selector);
69615
+ if (arm.pattern.kind === "type" && arm.pattern.bindingId)
69616
+ armVariables.set(arm.pattern.bindingId, selector);
69617
+ if (arm.guard)
69618
+ visitPointerPatternBindings(
69619
+ arm.guard,
69620
+ (id, value) => armVariables.set(
69621
+ id,
69622
+ pointerSource(ctx, value, armVariables, visitedGetterMemberIds)
69623
+ )
69624
+ );
69625
+ return pointerSource(
69626
+ ctx,
69627
+ arm.value,
69628
+ armVariables,
69629
+ visitedGetterMemberIds
69630
+ );
69631
+ });
69632
+ const first = sources2[0];
69633
+ return first && sources2.every((source) => source.ownership === first.ownership) ? first : unknownSource();
69634
+ }
68287
69635
  case "conditional" /* conditional */: {
68288
69636
  visitPointerPatternBindings(
68289
69637
  pointer.condition,
@@ -73383,7 +74731,7 @@ function schemaClassFromDocument(record4, context) {
73383
74731
  ...optionalDocsTextProperty(data.docsText, record4),
73384
74732
  declarationModifier: ordinalValue(
73385
74733
  data.modifier ?? 0,
73386
- ["concrete", "abstract", "sealed"],
74734
+ ["concrete", "abstract", "sealed", "closed"],
73387
74735
  record4,
73388
74736
  "modifier"
73389
74737
  ),
@@ -73433,7 +74781,7 @@ function schemaClassToDocument(schemaClass2) {
73433
74781
  schemaClass2.implementsInterfaceArguments
73434
74782
  ),
73435
74783
  uiVisibility: schemaClass2.hiddenInMemberSelector ? 1 : void 0,
73436
- modifier: schemaClass2.declarationModifier === "abstract" ? 1 : schemaClass2.declarationModifier === "sealed" ? 2 : void 0,
74784
+ modifier: { concrete: void 0, abstract: 1, sealed: 2, closed: 3 }[schemaClass2.declarationModifier],
73437
74785
  system: systemToDocument(schemaClass2.system),
73438
74786
  allowedStorage: schemaClass2.allowedStorage === null ? void 0 : CLASS_ALLOWED_STORAGE.indexOf(schemaClass2.allowedStorage),
73439
74787
  allowedStorageKeys: schemaClass2.allowedStorageKeys,