@casual-simulation/aux-common 3.1.8 → 3.1.9-alpha.3340590989

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/math/Vector2.js +6 -1
  2. package/math/Vector2.js.map +1 -1
  3. package/math/Vector3.js +6 -1
  4. package/math/Vector3.js.map +1 -1
  5. package/package.json +4 -2
  6. package/runtime/AuxCompiler.d.ts +74 -1
  7. package/runtime/AuxCompiler.js +332 -25
  8. package/runtime/AuxCompiler.js.map +1 -1
  9. package/runtime/AuxGlobalContext.d.ts +14 -4
  10. package/runtime/AuxGlobalContext.js +9 -1
  11. package/runtime/AuxGlobalContext.js.map +1 -1
  12. package/runtime/AuxLibrary.d.ts +191 -10
  13. package/runtime/AuxLibrary.js +172 -37
  14. package/runtime/AuxLibrary.js.map +1 -1
  15. package/runtime/AuxLibraryDefinitions.def +469 -82
  16. package/runtime/AuxRuntime.d.ts +66 -7
  17. package/runtime/AuxRuntime.js +976 -118
  18. package/runtime/AuxRuntime.js.map +1 -1
  19. package/runtime/AuxRuntimeDynamicImports.d.ts +14 -0
  20. package/runtime/AuxRuntimeDynamicImports.js +24 -0
  21. package/runtime/AuxRuntimeDynamicImports.js.map +1 -0
  22. package/runtime/CompiledBot.d.ts +59 -1
  23. package/runtime/CompiledBot.js +2 -0
  24. package/runtime/CompiledBot.js.map +1 -1
  25. package/runtime/RuntimeBot.d.ts +17 -0
  26. package/runtime/RuntimeBot.js +85 -5
  27. package/runtime/RuntimeBot.js.map +1 -1
  28. package/runtime/Transpiler.d.ts +21 -0
  29. package/runtime/Transpiler.js +27 -0
  30. package/runtime/Transpiler.js.map +1 -1
  31. package/runtime/Utils.d.ts +11 -0
  32. package/runtime/Utils.js +30 -1
  33. package/runtime/Utils.js.map +1 -1
  34. package/runtime/test/RuntimeTestHelpers.d.ts +5 -0
  35. package/runtime/test/RuntimeTestHelpers.js +11 -0
  36. package/runtime/test/RuntimeTestHelpers.js.map +1 -1
  37. package/test/TestHelpers.js +2 -2
  38. package/test/TestHelpers.js.map +1 -1
@@ -5,14 +5,23 @@
5
5
  // 3. Channel - These are manager objects which handle the persistence and runtime aspects of an AUX.
6
6
  // 4. Partitions - These are services which manage the persistence and realtime sync of the AUX data model.
7
7
  // 5. Runtimes - These are services which manage script execution and formula precalculation.
8
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
9
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
10
+ return new (P || (P = Promise))(function (resolve, reject) {
11
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
12
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
13
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
14
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
15
+ });
16
+ };
8
17
  import { hasValue, tagsOnBot, isFormula, isScript, isNumber, BOT_SPACE_TAG, botUpdated, isBot, ORIGINAL_OBJECT, DEFAULT_ENERGY, getBotSpace, ON_ACTION_ACTION_NAME, breakIntoIndividualEvents, ON_BOT_ADDED_ACTION_NAME, ON_ANY_BOTS_ADDED_ACTION_NAME, ON_ANY_BOTS_REMOVED_ACTION_NAME, ON_BOT_CHANGED_ACTION_NAME, ON_ANY_BOTS_CHANGED_ACTION_NAME, updatedBot, TAG_MASK_SPACE_PRIORITIES, CLEAR_CHANGES_SYMBOL, DNA_TAG_PREFIX, isRuntimeBot, createBot, ON_ERROR, action, isBotInDimension, asyncResult, registerBuiltinPortal, defineGlobalBot, isBotLink, parseBotLink, isBotDate, parseBotDate, formatBotDate, isTaggedString, parseTaggedString, parseNumber, isTaggedNumber, isBotVector, parseBotVector, formatBotVector, isBotRotation, parseBotRotation, formatBotRotation, } from '../bots';
9
18
  import { Subject, Subscription } from 'rxjs';
10
- import { AuxCompiler } from './AuxCompiler';
19
+ import { AuxCompiler, getInterpretableFunction, isInterpretableFunction, } from './AuxCompiler';
11
20
  import { addToContext, MemoryGlobalContext, removeFromContext, isInContext, } from './AuxGlobalContext';
12
21
  import { createDefaultLibrary, } from './AuxLibrary';
13
22
  import { createRuntimeBot, RealtimeEditMode, } from './RuntimeBot';
14
23
  import { RanOutOfEnergyError } from './AuxResults';
15
- import { convertToCopiableValue, DeepObjectError, } from './Utils';
24
+ import { convertToCopiableValue, DeepObjectError, isPromise, isRuntimePromise, markAsRuntimePromise, } from './Utils';
16
25
  import { DefaultRealtimeEditModeProvider, } from './AuxRealtimeEditModeProvider';
17
26
  import { sortBy, forOwn, merge, union } from 'lodash';
18
27
  import { tagValueHash } from '../aux-format-2/AuxOpTypes';
@@ -21,6 +30,41 @@ import { updateRuntimeVersion, } from './RuntimeStateVersion';
21
30
  import { replaceMacros } from './Transpiler';
22
31
  import { DateTime } from 'luxon';
23
32
  import { Rotation, Vector2, Vector3 } from '../math';
33
+ import { isGenerator, UNCOPIABLE, } from '@casual-simulation/js-interpreter/InterpreterUtils';
34
+ import { v4 as uuid } from 'uuid';
35
+ import { importInterpreter as _dynamicImportInterpreter } from './AuxRuntimeDynamicImports';
36
+ let Interpreter;
37
+ let DeclarativeEnvironmentRecord;
38
+ let DefinePropertyOrThrow;
39
+ let Descriptor;
40
+ let Value;
41
+ let hasModule = false;
42
+ let interpreterImportPromise;
43
+ export function registerInterpreterModule(module) {
44
+ hasModule = true;
45
+ Interpreter = module.Interpreter;
46
+ DeclarativeEnvironmentRecord = module.DeclarativeEnvironmentRecord;
47
+ DefinePropertyOrThrow = module.DefinePropertyOrThrow;
48
+ Descriptor = module.Descriptor;
49
+ Value = module.Value;
50
+ }
51
+ function importInterpreter() {
52
+ if (hasModule) {
53
+ return Promise.resolve();
54
+ }
55
+ if (interpreterImportPromise) {
56
+ return interpreterImportPromise;
57
+ }
58
+ else {
59
+ return (interpreterImportPromise = _importInterpreterCore());
60
+ }
61
+ }
62
+ function _importInterpreterCore() {
63
+ return __awaiter(this, void 0, void 0, function* () {
64
+ const module = yield _dynamicImportInterpreter();
65
+ registerInterpreterModule(module);
66
+ });
67
+ }
24
68
  /**
25
69
  * Defines an class that is able to manage the runtime state of an AUX.
26
70
  *
@@ -33,11 +77,16 @@ export class AuxRuntime {
33
77
  * @param libraryFactory
34
78
  * @param forceSignedScripts Whether to force the runtime to only allow scripts that are signed.
35
79
  * @param exemptSpaces The spaces that are exempt from requiring signed scripts.
80
+ * @param interpreter The interpreter that should be used for the runtime.
36
81
  */
37
- constructor(version, device, libraryFactory = createDefaultLibrary, editModeProvider = new DefaultRealtimeEditModeProvider(), forceSignedScripts = false, exemptSpaces = ['local', 'tempLocal'], forceSyncScripts = false) {
82
+ constructor(version, device, libraryFactory = createDefaultLibrary, editModeProvider = new DefaultRealtimeEditModeProvider(), forceSignedScripts = false, exemptSpaces = ['local', 'tempLocal'], forceSyncScripts = false, interpreter = null) {
38
83
  this._compiledState = {};
39
84
  this._existingMasks = {};
40
85
  this._compiler = new AuxCompiler();
86
+ this._stopState = null;
87
+ this._breakpoints = new Map();
88
+ this._currentStopCount = 0;
89
+ this._currentPromise = null;
41
90
  this._actionBatch = [];
42
91
  this._errorBatch = [];
43
92
  this._currentVersion = {
@@ -47,6 +96,8 @@ export class AuxRuntime {
47
96
  this._updatedBots = new Map();
48
97
  this._newBots = new Map();
49
98
  this._batchPending = false;
99
+ this._jobQueueCheckPending = false;
100
+ this._jobQueueCheckCount = 0;
50
101
  this._processingErrors = false;
51
102
  this._portalBots = new Map();
52
103
  this._builtinPortalBots = [];
@@ -70,7 +121,8 @@ export class AuxRuntime {
70
121
  this._forceSyncScripts = false;
71
122
  this._currentDebugger = null;
72
123
  this._libraryFactory = libraryFactory;
73
- this._globalContext = new MemoryGlobalContext(version, device, this, this);
124
+ this._interpreter = interpreter;
125
+ this._globalContext = new MemoryGlobalContext(version, device, this, this, this);
74
126
  this._forceSyncScripts = forceSyncScripts;
75
127
  this._globalContext.mockAsyncActions = forceSyncScripts;
76
128
  this._library = merge(libraryFactory(this._globalContext), {
@@ -86,6 +138,7 @@ export class AuxRuntime {
86
138
  this._exemptSpaces = exemptSpaces;
87
139
  this._onActions = new Subject();
88
140
  this._onErrors = new Subject();
141
+ this._onRuntimeStop = new Subject();
89
142
  let sub = (this._sub = new Subscription(() => {
90
143
  this._globalContext.cancelAllBotTimers();
91
144
  }));
@@ -137,6 +190,24 @@ export class AuxRuntime {
137
190
  },
138
191
  });
139
192
  this._globalContext.global = this._globalObject;
193
+ if (this._interpreter) {
194
+ // Use the interpreted versions of APIs
195
+ this._interpretedApi = Object.assign({}, this._library.api);
196
+ this._interpretedTagSpecificApi = Object.assign({}, this._library.tagSpecificApi);
197
+ for (let key in this._interpretedApi) {
198
+ const val = this._interpretedApi[key];
199
+ if (isInterpretableFunction(val)) {
200
+ this._interpretedApi[key] = getInterpretableFunction(val);
201
+ }
202
+ }
203
+ for (let key in this._interpretedTagSpecificApi) {
204
+ const val = this._interpretedTagSpecificApi[key];
205
+ if (isInterpretableFunction(val)) {
206
+ this._interpretedTagSpecificApi[key] =
207
+ getInterpretableFunction(val);
208
+ }
209
+ }
210
+ }
140
211
  }
141
212
  get forceSignedScripts() {
142
213
  return this._forceSignedScripts;
@@ -150,6 +221,9 @@ export class AuxRuntime {
150
221
  get globalObject() {
151
222
  return this._globalObject;
152
223
  }
224
+ get canTriggerBreakpoint() {
225
+ return !!this._interpreter && this._interpreter.debugging;
226
+ }
153
227
  getShoutTimers() {
154
228
  return {};
155
229
  }
@@ -196,6 +270,12 @@ export class AuxRuntime {
196
270
  get onErrors() {
197
271
  return this._onErrors;
198
272
  }
273
+ /**
274
+ * An observable that resolves whenever the runtime pauses in a script.
275
+ */
276
+ get onRuntimeStop() {
277
+ return this._onRuntimeStop;
278
+ }
199
279
  /**
200
280
  * Processes the given bot actions and dispatches the resulting actions in the future.
201
281
  * @param actions The actions to process.
@@ -209,85 +289,408 @@ export class AuxRuntime {
209
289
  return this._currentDebugger;
210
290
  }
211
291
  _createDebugger(options) {
212
- const runtime = new AuxRuntime(this._globalContext.version, this._globalContext.device, this._libraryFactory, this._editModeProvider, this._forceSignedScripts, this._exemptSpaces, !(options === null || options === void 0 ? void 0 : options.allowAsynchronousScripts));
213
- runtime._autoBatch = false;
214
- let idCount = 0;
215
- if (!(options === null || options === void 0 ? void 0 : options.useRealUUIDs)) {
216
- runtime._globalContext.uuid = () => {
217
- idCount += 1;
218
- return `uuid-${idCount}`;
292
+ return __awaiter(this, void 0, void 0, function* () {
293
+ const forceSyncScripts = typeof (options === null || options === void 0 ? void 0 : options.allowAsynchronousScripts) === 'boolean'
294
+ ? !options.allowAsynchronousScripts
295
+ : false;
296
+ yield importInterpreter();
297
+ const interpreter = (options === null || options === void 0 ? void 0 : options.pausable) ? new Interpreter() : null;
298
+ const runtime = new AuxRuntime(this._globalContext.version, this._globalContext.device, this._libraryFactory, this._editModeProvider, this._forceSignedScripts, this._exemptSpaces, forceSyncScripts, interpreter);
299
+ runtime._autoBatch = false;
300
+ let idCount = 0;
301
+ if (!(options === null || options === void 0 ? void 0 : options.useRealUUIDs)) {
302
+ runtime._globalContext.uuid = () => {
303
+ idCount += 1;
304
+ return `uuid-${idCount}`;
305
+ };
306
+ }
307
+ let allActions = [];
308
+ let allErrors = [];
309
+ let create;
310
+ if (interpreter &&
311
+ isInterpretableFunction(runtime._library.tagSpecificApi.create)) {
312
+ const func = getInterpretableFunction(runtime._library.tagSpecificApi.create)({
313
+ bot: null,
314
+ config: null,
315
+ creator: null,
316
+ tag: null,
317
+ });
318
+ create = (...args) => {
319
+ const result = func(...args);
320
+ if (isGenerator(result)) {
321
+ return runtime._processGenerator(result);
322
+ }
323
+ return result;
324
+ };
325
+ }
326
+ else {
327
+ create = runtime._library.tagSpecificApi.create({
328
+ bot: null,
329
+ config: null,
330
+ creator: null,
331
+ tag: null,
332
+ });
333
+ }
334
+ const isCommonAction = (action) => {
335
+ return !(action.type === 'add_bot' ||
336
+ action.type === 'remove_bot' ||
337
+ action.type === 'update_bot' ||
338
+ action.type === 'apply_state');
219
339
  };
220
- }
221
- let allActions = [];
222
- let allErrors = [];
223
- let create = runtime._library.tagSpecificApi.create({
224
- bot: null,
225
- config: null,
226
- creator: null,
227
- tag: null,
340
+ const getAllActions = () => {
341
+ const actions = runtime._processUnbatchedActions();
342
+ allActions.push(...actions);
343
+ return allActions;
344
+ };
345
+ // The config bot is always ID 0 in debuggers
346
+ const configBotId = (options === null || options === void 0 ? void 0 : options.useRealUUIDs)
347
+ ? runtime.context.uuid()
348
+ : 'uuid-0';
349
+ const configBotTags = (options === null || options === void 0 ? void 0 : options.configBot)
350
+ ? isBot(options === null || options === void 0 ? void 0 : options.configBot)
351
+ ? options.configBot.tags
352
+ : options.configBot
353
+ : {};
354
+ runtime.context.createBot(createBot(configBotId, configBotTags, 'tempLocal'));
355
+ runtime.process(this._builtinPortalBots.map((b) => registerBuiltinPortal(b)));
356
+ runtime.userId = configBotId;
357
+ const api = Object.assign({}, runtime._library.api);
358
+ if (interpreter) {
359
+ for (let key in runtime._library.api) {
360
+ const val = runtime._library.api[key];
361
+ if (isInterpretableFunction(val)) {
362
+ const func = getInterpretableFunction(val);
363
+ api[key] = (...args) => {
364
+ const result = func(...args);
365
+ if (isGenerator(result)) {
366
+ return runtime._processGenerator(result);
367
+ }
368
+ return result;
369
+ };
370
+ }
371
+ }
372
+ }
373
+ if (interpreter && (options === null || options === void 0 ? void 0 : options.pausable)) {
374
+ interpreter.debugging = true;
375
+ }
376
+ const debug = Object.assign(Object.assign({ [UNCOPIABLE]: true }, api), { getAllActions, getCommonActions: () => {
377
+ return getAllActions().filter(isCommonAction);
378
+ }, getBotActions: () => {
379
+ return getAllActions().filter((a) => !isCommonAction(a));
380
+ }, getErrors: () => {
381
+ const errors = runtime._processUnbatchedErrors();
382
+ allErrors.push(...errors);
383
+ return allErrors;
384
+ }, setPauseTrigger(b, tag, options) {
385
+ var _a, _b, _c;
386
+ if (typeof b === 'object' && 'triggerId' in b) {
387
+ runtime.setBreakpoint({
388
+ id: b.triggerId,
389
+ botId: b.botId,
390
+ tag: b.tag,
391
+ lineNumber: b.lineNumber,
392
+ columnNumber: b.columnNumber,
393
+ states: (_a = b.states) !== null && _a !== void 0 ? _a : ['before'],
394
+ disabled: !((_b = b.enabled) !== null && _b !== void 0 ? _b : true),
395
+ });
396
+ return b;
397
+ }
398
+ else {
399
+ const id = isBot(b) ? b.id : b;
400
+ const trigger = Object.assign({ triggerId: uuid(), botId: id, tag: tag }, options);
401
+ runtime.setBreakpoint({
402
+ id: trigger.triggerId,
403
+ botId: id,
404
+ tag: tag,
405
+ lineNumber: trigger.lineNumber,
406
+ columnNumber: trigger.columnNumber,
407
+ states: (_c = trigger.states) !== null && _c !== void 0 ? _c : ['before'],
408
+ disabled: false,
409
+ });
410
+ return trigger;
411
+ }
412
+ },
413
+ removePauseTrigger(triggerOrId) {
414
+ let id = typeof triggerOrId === 'string'
415
+ ? triggerOrId
416
+ : triggerOrId.triggerId;
417
+ runtime.removeBreakpoint(id);
418
+ },
419
+ disablePauseTrigger(triggerOrId) {
420
+ var _a;
421
+ if (typeof triggerOrId === 'string') {
422
+ let trigger = runtime._breakpoints.get(triggerOrId);
423
+ if (trigger) {
424
+ trigger.disabled = true;
425
+ }
426
+ }
427
+ else {
428
+ runtime.setBreakpoint({
429
+ id: triggerOrId.triggerId,
430
+ botId: triggerOrId.botId,
431
+ tag: triggerOrId.tag,
432
+ lineNumber: triggerOrId.lineNumber,
433
+ columnNumber: triggerOrId.columnNumber,
434
+ states: (_a = triggerOrId.states) !== null && _a !== void 0 ? _a : ['before'],
435
+ disabled: true,
436
+ });
437
+ }
438
+ },
439
+ enablePauseTrigger(triggerOrId) {
440
+ var _a;
441
+ if (typeof triggerOrId === 'string') {
442
+ let trigger = runtime._breakpoints.get(triggerOrId);
443
+ if (trigger) {
444
+ trigger.disabled = false;
445
+ }
446
+ }
447
+ else {
448
+ runtime.setBreakpoint({
449
+ id: triggerOrId.triggerId,
450
+ botId: triggerOrId.botId,
451
+ tag: triggerOrId.tag,
452
+ lineNumber: triggerOrId.lineNumber,
453
+ columnNumber: triggerOrId.columnNumber,
454
+ states: (_a = triggerOrId.states) !== null && _a !== void 0 ? _a : ['before'],
455
+ disabled: false,
456
+ });
457
+ }
458
+ },
459
+ listPauseTriggers() {
460
+ let triggers = [];
461
+ for (let breakpoint of runtime._breakpoints.values()) {
462
+ triggers.push({
463
+ triggerId: breakpoint.id,
464
+ botId: breakpoint.botId,
465
+ tag: breakpoint.tag,
466
+ columnNumber: breakpoint.columnNumber,
467
+ lineNumber: breakpoint.lineNumber,
468
+ states: breakpoint.states.slice(),
469
+ enabled: !breakpoint.disabled,
470
+ });
471
+ }
472
+ return triggers;
473
+ },
474
+ listCommonPauseTriggers(botOrId, tag) {
475
+ const id = typeof botOrId === 'string' ? botOrId : botOrId.id;
476
+ const bot = runtime.currentState[id];
477
+ const func = bot.listeners[tag];
478
+ if (!func) {
479
+ return [];
480
+ }
481
+ return runtime._compiler.listPossibleBreakpoints(func, runtime._interpreter);
482
+ },
483
+ onPause(callback) {
484
+ runtime.onRuntimeStop.subscribe((stop) => {
485
+ const pause = {
486
+ pauseId: stop.stopId,
487
+ state: stop.state,
488
+ callStack: stop.stack.map((s) => {
489
+ const callSite = s.callSite;
490
+ const funcName = callSite.getFunctionName();
491
+ let funcLocation = {};
492
+ if (funcName) {
493
+ const f = runtime._functionMap.get(funcName);
494
+ if (f) {
495
+ funcLocation.name =
496
+ f.metadata.diagnosticFunctionName;
497
+ const location = runtime._compiler.calculateOriginalLineLocation(f, {
498
+ lineNumber: callSite.lineNumber,
499
+ column: callSite.columnNumber,
500
+ });
501
+ funcLocation.lineNumber =
502
+ location.lineNumber + 1;
503
+ funcLocation.columnNumber =
504
+ location.column + 1;
505
+ const tagName = f.metadata.context
506
+ .tag;
507
+ const bot = f.metadata.context.bot;
508
+ if (bot) {
509
+ funcLocation.botId = bot.id;
510
+ }
511
+ if (tagName) {
512
+ funcLocation.tag = tagName;
513
+ }
514
+ }
515
+ else {
516
+ funcLocation.name = funcName;
517
+ }
518
+ }
519
+ if (!hasValue(funcLocation.lineNumber) &&
520
+ !hasValue(funcLocation.columnNumber) &&
521
+ hasValue(callSite.lineNumber) &&
522
+ hasValue(callSite.columnNumber)) {
523
+ funcLocation.lineNumber = callSite.lineNumber;
524
+ funcLocation.columnNumber =
525
+ callSite.columnNumber;
526
+ }
527
+ if (!hasValue(funcLocation.lineNumber) &&
528
+ !hasValue(funcLocation.columnNumber) &&
529
+ !hasValue(funcLocation.name)) {
530
+ funcLocation = null;
531
+ }
532
+ const ret = {
533
+ location: funcLocation,
534
+ listVariables() {
535
+ let variables = [];
536
+ if (s.LexicalEnvironment instanceof
537
+ DeclarativeEnvironmentRecord) {
538
+ addBindingsFromEnvironment(s.LexicalEnvironment, 'block');
539
+ }
540
+ if (s.VariableEnvironment instanceof
541
+ DeclarativeEnvironmentRecord) {
542
+ addBindingsFromEnvironment(s.VariableEnvironment, 'frame');
543
+ let parent = s.VariableEnvironment.OuterEnv;
544
+ while (parent) {
545
+ if (parent instanceof
546
+ DeclarativeEnvironmentRecord) {
547
+ addBindingsFromEnvironment(parent, 'closure');
548
+ }
549
+ parent = parent.OuterEnv;
550
+ }
551
+ }
552
+ return variables;
553
+ function addBindingsFromEnvironment(env, scope) {
554
+ for (let [nameValue, binding,] of env.bindings.entries()) {
555
+ const name = interpreter.copyFromValue(nameValue);
556
+ const initialized = !!binding.initialized;
557
+ const mutable = !!binding.mutable;
558
+ const value = initialized
559
+ ? interpreter.reverseProxyObject(binding.value, false)
560
+ : undefined;
561
+ const variable = {
562
+ name,
563
+ value,
564
+ writable: mutable,
565
+ scope,
566
+ };
567
+ if (!initialized) {
568
+ variable.initialized = false;
569
+ }
570
+ variables.push(variable);
571
+ }
572
+ }
573
+ },
574
+ setVariableValue(name, value) {
575
+ if (s.LexicalEnvironment instanceof
576
+ DeclarativeEnvironmentRecord) {
577
+ const nameValue = interpreter.copyToValue(name);
578
+ const proxiedValue = interpreter.proxyObject(value);
579
+ if (nameValue.Type !== 'normal') {
580
+ throw interpreter.copyFromValue(nameValue.Value);
581
+ }
582
+ if (proxiedValue.Type !== 'normal') {
583
+ throw interpreter.copyFromValue(proxiedValue.Value);
584
+ }
585
+ const result = s.LexicalEnvironment.SetMutableBinding(nameValue.Value, proxiedValue.Value, Value.true);
586
+ if (result.Type !== 'normal') {
587
+ throw interpreter.copyFromValue(result.Value);
588
+ }
589
+ return interpreter.copyFromValue(result.Value);
590
+ }
591
+ },
592
+ };
593
+ return ret;
594
+ }),
595
+ trigger: {
596
+ triggerId: stop.breakpoint.id,
597
+ botId: stop.breakpoint.botId,
598
+ tag: stop.breakpoint.tag,
599
+ lineNumber: stop.breakpoint.lineNumber,
600
+ columnNumber: stop.breakpoint.columnNumber,
601
+ states: stop.breakpoint.states,
602
+ },
603
+ };
604
+ callback(pause);
605
+ });
606
+ },
607
+ resume(pause) {
608
+ runtime.continueAfterStop(pause.pauseId);
609
+ },
610
+ create });
611
+ runtime._currentDebugger = debug;
612
+ this._scheduleJobQueueCheck();
613
+ return debug;
228
614
  });
229
- const isCommonAction = (action) => {
230
- return !(action.type === 'add_bot' ||
231
- action.type === 'remove_bot' ||
232
- action.type === 'update_bot' ||
233
- action.type === 'apply_state');
234
- };
235
- const getAllActions = () => {
236
- const actions = runtime._processUnbatchedActions();
237
- allActions.push(...actions);
238
- return allActions;
239
- };
240
- // The config bot is always ID 0 in debuggers
241
- const configBotId = (options === null || options === void 0 ? void 0 : options.useRealUUIDs)
242
- ? runtime.context.uuid()
243
- : 'uuid-0';
244
- const configBotTags = (options === null || options === void 0 ? void 0 : options.configBot)
245
- ? isBot(options === null || options === void 0 ? void 0 : options.configBot)
246
- ? options.configBot.tags
247
- : options.configBot
248
- : {};
249
- runtime.context.createBot(createBot(configBotId, configBotTags, 'tempLocal'));
250
- runtime.process(this._builtinPortalBots.map((b) => registerBuiltinPortal(b)));
251
- runtime.userId = configBotId;
252
- const debug = Object.assign(Object.assign({}, runtime._library.api), { getAllActions, getCommonActions: () => {
253
- return getAllActions().filter(isCommonAction);
254
- }, getBotActions: () => {
255
- return getAllActions().filter((a) => !isCommonAction(a));
256
- }, getErrors: () => {
257
- const errors = runtime._processUnbatchedErrors();
258
- allErrors.push(...errors);
259
- return allErrors;
260
- }, create });
261
- runtime._currentDebugger = debug;
262
- return debug;
263
615
  }
264
616
  _processCore(actions) {
265
- for (let action of actions) {
266
- let { rejected, newActions } = this._rejectAction(action);
267
- for (let newAction of newActions) {
268
- this._processAction(newAction);
617
+ const _this = this;
618
+ function handleRejection(action, rejection) {
619
+ let promise = processListOfMaybePromises(null, rejection.newActions, (action) => {
620
+ return _this._processAction(action);
621
+ });
622
+ if (rejection.rejected) {
623
+ return;
269
624
  }
270
- if (rejected) {
271
- continue;
625
+ if (promise) {
626
+ return markAsRuntimePromise(promise.then((p) => _this._processAction(action)));
627
+ }
628
+ else {
629
+ return _this._processAction(action);
272
630
  }
273
- this._processAction(action);
274
631
  }
632
+ return processListOfMaybePromises(null, actions, (action) => {
633
+ let rejection = this._rejectAction(action);
634
+ if (isRuntimePromise(rejection)) {
635
+ return markAsRuntimePromise(rejection.then((result) => handleRejection(action, result)));
636
+ }
637
+ else {
638
+ return handleRejection(action, rejection);
639
+ }
640
+ });
275
641
  }
276
642
  _processAction(action) {
277
643
  if (action.type === 'action') {
278
644
  const result = this._shout(action.eventName, action.botIds, action.argument, false);
279
- this._processCore(result.actions);
645
+ if (isRuntimePromise(result)) {
646
+ return markAsRuntimePromise(result.then((result) => this._processCore(result.actions)));
647
+ }
648
+ else {
649
+ return this._processCore(result.actions);
650
+ }
280
651
  }
281
652
  else if (action.type === 'run_script') {
282
653
  const result = this._execute(action.script, false, false);
283
- this._processCore(result.actions);
284
- if (hasValue(action.taskId)) {
285
- this._globalContext.resolveTask(action.taskId, result.result, false);
654
+ if (isRuntimePromise(result)) {
655
+ return markAsRuntimePromise(result.then((result) => {
656
+ const p = this._processCore(result.actions);
657
+ if (isPromise(p)) {
658
+ return p.then(() => {
659
+ if (hasValue(action.taskId)) {
660
+ this._globalContext.resolveTask(action.taskId, result.result, false);
661
+ }
662
+ });
663
+ }
664
+ else {
665
+ if (hasValue(action.taskId)) {
666
+ if (this._globalContext.resolveTask(action.taskId, result.result, false)) {
667
+ this._scheduleJobQueueCheck();
668
+ }
669
+ }
670
+ }
671
+ }));
672
+ }
673
+ else {
674
+ const p = this._processCore(result.actions);
675
+ if (isRuntimePromise(p)) {
676
+ return markAsRuntimePromise(p.then(() => {
677
+ if (hasValue(action.taskId)) {
678
+ if (this._globalContext.resolveTask(action.taskId, result.result, false)) {
679
+ this._scheduleJobQueueCheck();
680
+ }
681
+ }
682
+ }));
683
+ }
684
+ if (hasValue(action.taskId)) {
685
+ if (this._globalContext.resolveTask(action.taskId, result.result, false)) {
686
+ this._scheduleJobQueueCheck();
687
+ }
688
+ }
286
689
  }
287
690
  }
288
691
  else if (action.type === 'apply_state') {
289
692
  const events = breakIntoIndividualEvents(this.currentState, action);
290
- this._processCore(events);
693
+ return this._processCore(events);
291
694
  }
292
695
  else if (action.type === 'async_result') {
293
696
  const value = action.mapBotsInResult === true
@@ -296,21 +699,33 @@ export class AuxRuntime {
296
699
  if (!this._globalContext.resolveTask(action.taskId, value, false)) {
297
700
  this._actionBatch.push(action);
298
701
  }
702
+ else {
703
+ this._scheduleJobQueueCheck();
704
+ }
299
705
  }
300
706
  else if (action.type === 'async_error') {
301
707
  if (!this._globalContext.rejectTask(action.taskId, action.error, false)) {
302
708
  this._actionBatch.push(action);
303
709
  }
710
+ else {
711
+ this._scheduleJobQueueCheck();
712
+ }
304
713
  }
305
714
  else if (action.type === 'device_result') {
306
715
  if (!this._globalContext.resolveTask(action.taskId, action.result, true)) {
307
716
  this._actionBatch.push(action);
308
717
  }
718
+ else {
719
+ this._scheduleJobQueueCheck();
720
+ }
309
721
  }
310
722
  else if (action.type === 'device_error') {
311
723
  if (!this._globalContext.rejectTask(action.taskId, action.error, true)) {
312
724
  this._actionBatch.push(action);
313
725
  }
726
+ else {
727
+ this._scheduleJobQueueCheck();
728
+ }
314
729
  }
315
730
  else if (action.type === 'register_custom_app') {
316
731
  this._registerPortalBot(action.appId, action.botId);
@@ -330,7 +745,7 @@ export class AuxRuntime {
330
745
  this._actionBatch.push(action);
331
746
  }
332
747
  if (hasValue(action.taskId)) {
333
- this._processCore([asyncResult(action.taskId, null)]);
748
+ return this._processCore([asyncResult(action.taskId, null)]);
334
749
  }
335
750
  }
336
751
  else {
@@ -342,35 +757,76 @@ export class AuxRuntime {
342
757
  this._portalBots.set(portalId, botId);
343
758
  if (!hadPortalBot) {
344
759
  const variableName = `${portalId}Bot`;
760
+ const getValue = () => {
761
+ const botId = this._portalBots.get(portalId);
762
+ if (hasValue(botId)) {
763
+ return this.context.state[botId];
764
+ }
765
+ else {
766
+ return undefined;
767
+ }
768
+ };
345
769
  Object.defineProperty(this._globalObject, variableName, {
346
- get: () => {
347
- const botId = this._portalBots.get(portalId);
348
- if (hasValue(botId)) {
349
- return this.context.state[botId];
350
- }
351
- else {
352
- return undefined;
353
- }
354
- },
770
+ get: getValue,
355
771
  enumerable: false,
356
772
  configurable: true,
357
773
  });
774
+ if (this._interpreter) {
775
+ const proxiedGetResult = this._interpreter.proxyObject(getValue);
776
+ if (proxiedGetResult.Type !== 'normal') {
777
+ throw this._interpreter.copyFromValue(proxiedGetResult.Value);
778
+ }
779
+ DefinePropertyOrThrow(this._interpreter.realm.GlobalObject, new Value(variableName), new Descriptor({
780
+ Get: proxiedGetResult.Value,
781
+ Configurable: Value.true,
782
+ }));
783
+ }
358
784
  }
359
785
  }
360
786
  _rejectAction(action) {
361
787
  const result = this._shout(ON_ACTION_ACTION_NAME, null, {
362
788
  action: action,
363
789
  }, false);
364
- let rejected = false;
365
- for (let i = 0; i < result.actions.length; i++) {
366
- const a = result.actions[i];
367
- if (a.type === 'reject' && a.actions.indexOf(action) >= 0) {
368
- rejected = true;
369
- result.actions.splice(i, 1);
370
- break;
790
+ if (isRuntimePromise(result)) {
791
+ return markAsRuntimePromise(result.then((result) => {
792
+ return handleResult(result);
793
+ }));
794
+ }
795
+ return handleResult(result);
796
+ function handleResult(result) {
797
+ let rejected = false;
798
+ for (let i = 0; i < result.actions.length; i++) {
799
+ const a = result.actions[i];
800
+ if (a.type === 'reject' && a.actions.indexOf(action) >= 0) {
801
+ rejected = true;
802
+ result.actions.splice(i, 1);
803
+ break;
804
+ }
371
805
  }
806
+ return { rejected, newActions: result.actions };
807
+ }
808
+ }
809
+ /**
810
+ * Executes the given function based on the current execution state of the runtime.
811
+ * If the runtime is stopped, then the given function will be executed after the current promise finishes.
812
+ * If the runtime is executing normally, then the given function will be executed immediately.
813
+ * Returns the function result if the function executes immediately,
814
+ * or returns a runtime promise if the function executes after the current promise.
815
+ *
816
+ * This function essentially forces the given function to execute synchronously with respect to other functions wrapped with this function.
817
+ *
818
+ * @param func The function to execute.
819
+ *
820
+ */
821
+ _wrapWithCurrentPromise(func) {
822
+ if (this._stopState && isRuntimePromise(this._currentPromise)) {
823
+ // We have hit a breakpoint,
824
+ // only trigger this shout after the current state has finished.
825
+ return (this._currentPromise = markAsRuntimePromise(this._currentPromise.then(() => {
826
+ return func();
827
+ })));
372
828
  }
373
- return { rejected, newActions: result.actions };
829
+ return (this._currentPromise = func());
374
830
  }
375
831
  /**
376
832
  * Executes a shout with the given event name on the given bot IDs with the given argument.
@@ -380,25 +836,64 @@ export class AuxRuntime {
380
836
  * @param arg The argument to include in the shout.
381
837
  */
382
838
  shout(eventName, botIds, arg) {
383
- return this._shout(eventName, botIds, arg, true);
839
+ return this._synchronousShout(eventName, botIds, arg, true, true);
840
+ }
841
+ /**
842
+ * Executes the given shout synchronously with respect to other scripts that may be running or paused.
843
+ * @param eventName The name of the event that should be executed.
844
+ * @param botIds The IDs of the bots that the shout should be sent to.
845
+ * @param arg The argument that should be sent with the shout.
846
+ * @param batch Whether to batch events.
847
+ * @param resetEnergy Whether to reset the runtime energy before executing the shout.
848
+ */
849
+ _synchronousShout(eventName, botIds, arg, batch, resetEnergy = true) {
850
+ return this._wrapWithCurrentPromise(() => {
851
+ return this._shout(eventName, botIds, arg, batch, resetEnergy);
852
+ });
384
853
  }
385
854
  _shout(eventName, botIds, arg, batch, resetEnergy = true) {
386
855
  try {
387
856
  arg = this._mapBotsToRuntimeBots(arg);
857
+ if (this._interpreter) {
858
+ const result = this._interpreter.proxyObject(arg);
859
+ if (result.Type !== 'normal') {
860
+ throw new Error(`Unable to proxy shout argument!`);
861
+ }
862
+ arg = result.Value;
863
+ }
388
864
  }
389
865
  catch (err) {
390
866
  arg = err;
391
867
  }
392
- const { result, actions, errors } = this._batchScriptResults(() => {
393
- const results = hasValue(botIds)
394
- ? this._library.api.whisper(botIds, eventName, arg)
395
- : this._library.api.shout(eventName, arg);
396
- return results;
868
+ const result = this._batchScriptResults(() => {
869
+ if (this.canTriggerBreakpoint) {
870
+ const results = (hasValue(botIds)
871
+ ? getInterpretableFunction(this._library.api.whisper)(botIds, eventName, arg)
872
+ : getInterpretableFunction(this._library.api.shout)(eventName, arg));
873
+ return this._processGenerator(results);
874
+ }
875
+ else {
876
+ const results = hasValue(botIds)
877
+ ? this._library.api.whisper(botIds, eventName, arg)
878
+ : this._library.api.shout(eventName, arg);
879
+ this._scheduleJobQueueCheck();
880
+ return results;
881
+ }
397
882
  }, batch, resetEnergy);
883
+ if (isRuntimePromise(result)) {
884
+ return markAsRuntimePromise(result.then(({ actions, errors, result }) => {
885
+ return {
886
+ actions,
887
+ errors,
888
+ results: result,
889
+ listeners: [],
890
+ };
891
+ }));
892
+ }
398
893
  return {
399
- actions,
400
- errors,
401
- results: result,
894
+ actions: result.actions,
895
+ errors: result.errors,
896
+ results: result.result,
402
897
  listeners: [],
403
898
  };
404
899
  }
@@ -407,7 +902,9 @@ export class AuxRuntime {
407
902
  * @param script The script to run.
408
903
  */
409
904
  execute(script) {
410
- return this._execute(script, true, true);
905
+ return this._wrapWithCurrentPromise(() => {
906
+ return this._execute(script, true, true);
907
+ });
411
908
  }
412
909
  _execute(script, batch, resetEnergy) {
413
910
  let fn;
@@ -491,8 +988,8 @@ export class AuxRuntime {
491
988
  _sendOnBotsAddedShouts(newBots, nextUpdate) {
492
989
  if (newBots && nextUpdate.addedBots.length > 0) {
493
990
  try {
494
- this._shout(ON_BOT_ADDED_ACTION_NAME, nextUpdate.addedBots, undefined, true, false);
495
- this._shout(ON_ANY_BOTS_ADDED_ACTION_NAME, null, {
991
+ this._synchronousShout(ON_BOT_ADDED_ACTION_NAME, nextUpdate.addedBots, undefined, true, false);
992
+ this._synchronousShout(ON_ANY_BOTS_ADDED_ACTION_NAME, null, {
496
993
  bots: newBots.map(([bot, precalc]) => bot),
497
994
  }, true, false);
498
995
  }
@@ -509,15 +1006,47 @@ export class AuxRuntime {
509
1006
  _sendOnBotsRemovedShouts(botIds) {
510
1007
  if (botIds.length > 0) {
511
1008
  try {
1009
+ let promise;
512
1010
  for (let bot of botIds) {
513
1011
  const watchers = this._globalContext.getWatchersForBot(bot);
514
- for (let watcher of watchers) {
515
- watcher.handler();
1012
+ promise = processListOfMaybePromises(promise, watchers, (watcher) => {
1013
+ const generator = watcher.handler();
1014
+ if (isGenerator(generator)) {
1015
+ return this._processGenerator(generator);
1016
+ }
1017
+ });
1018
+ }
1019
+ if (promise) {
1020
+ return markAsRuntimePromise(promise
1021
+ .then(() => {
1022
+ return this._synchronousShout(ON_ANY_BOTS_REMOVED_ACTION_NAME, null, {
1023
+ botIDs: botIds,
1024
+ }, true, false);
1025
+ })
1026
+ .catch((err) => {
1027
+ if (!(err instanceof RanOutOfEnergyError)) {
1028
+ throw err;
1029
+ }
1030
+ else {
1031
+ console.warn(err);
1032
+ }
1033
+ }));
1034
+ }
1035
+ else {
1036
+ const maybePromise = this._synchronousShout(ON_ANY_BOTS_REMOVED_ACTION_NAME, null, {
1037
+ botIDs: botIds,
1038
+ }, true, false);
1039
+ if (isRuntimePromise(maybePromise)) {
1040
+ return markAsRuntimePromise(maybePromise.catch((err) => {
1041
+ if (!(err instanceof RanOutOfEnergyError)) {
1042
+ throw err;
1043
+ }
1044
+ else {
1045
+ console.warn(err);
1046
+ }
1047
+ }));
516
1048
  }
517
1049
  }
518
- this._shout(ON_ANY_BOTS_REMOVED_ACTION_NAME, null, {
519
- botIDs: botIds,
520
- }, true, false);
521
1050
  }
522
1051
  catch (err) {
523
1052
  if (!(err instanceof RanOutOfEnergyError)) {
@@ -532,19 +1061,52 @@ export class AuxRuntime {
532
1061
  _sendOnBotsChangedShouts(updates) {
533
1062
  if (updates && updates.length > 0) {
534
1063
  try {
535
- for (let update of updates) {
1064
+ let promise = processListOfMaybePromises(null, updates, (update) => {
536
1065
  if (!update) {
537
- continue;
1066
+ return;
538
1067
  }
539
- this._shout(ON_BOT_CHANGED_ACTION_NAME, [update.bot.id], {
1068
+ let promise = this._synchronousShout(ON_BOT_CHANGED_ACTION_NAME, [update.bot.id], {
540
1069
  tags: update.tags,
541
1070
  }, true, false);
542
1071
  const watchers = this._globalContext.getWatchersForBot(update.bot.id);
543
- for (let watcher of watchers) {
544
- watcher.handler();
1072
+ return processListOfMaybePromises(promise, watchers, (watcher) => {
1073
+ const generator = watcher.handler();
1074
+ if (isGenerator(generator)) {
1075
+ return this._processGenerator(generator);
1076
+ }
1077
+ return generator;
1078
+ });
1079
+ });
1080
+ if (isPromise(promise)) {
1081
+ return promise
1082
+ .then(() => {
1083
+ return this._synchronousShout(ON_ANY_BOTS_CHANGED_ACTION_NAME, null, updates, true, false);
1084
+ })
1085
+ .catch((err) => {
1086
+ if (!(err instanceof RanOutOfEnergyError)) {
1087
+ throw err;
1088
+ }
1089
+ else {
1090
+ console.warn(err);
1091
+ }
1092
+ });
1093
+ }
1094
+ else {
1095
+ const maybePromise = this._synchronousShout(ON_ANY_BOTS_CHANGED_ACTION_NAME, null, updates, true, false);
1096
+ if (isPromise(maybePromise)) {
1097
+ return maybePromise.catch((err) => {
1098
+ if (!(err instanceof RanOutOfEnergyError)) {
1099
+ throw err;
1100
+ }
1101
+ else {
1102
+ console.warn(err);
1103
+ }
1104
+ });
1105
+ }
1106
+ else {
1107
+ return maybePromise;
545
1108
  }
546
1109
  }
547
- this._shout(ON_ANY_BOTS_CHANGED_ACTION_NAME, null, updates, true, false);
548
1110
  }
549
1111
  catch (err) {
550
1112
  if (!(err instanceof RanOutOfEnergyError)) {
@@ -573,7 +1135,7 @@ export class AuxRuntime {
573
1135
  if (!userBot) {
574
1136
  return;
575
1137
  }
576
- for (let portal of portals) {
1138
+ return processListOfMaybePromises(null, portals, (portal) => {
577
1139
  const dimension = userBot.values[portal];
578
1140
  let hasChange = false;
579
1141
  if (hasValue(dimension)) {
@@ -617,11 +1179,14 @@ export class AuxRuntime {
617
1179
  }
618
1180
  if (hasChange) {
619
1181
  const watchers = this._globalContext.getWatchersForPortal(portal);
620
- for (let watcher of watchers) {
621
- watcher.handler();
622
- }
1182
+ return processListOfMaybePromises(null, watchers, (watcher) => {
1183
+ const generator = watcher.handler();
1184
+ if (isGenerator(generator)) {
1185
+ return this._processGenerator(generator);
1186
+ }
1187
+ });
623
1188
  }
624
- }
1189
+ });
625
1190
  }
626
1191
  _addBotsToState(bots, nextUpdate) {
627
1192
  let newBots = [];
@@ -679,6 +1244,10 @@ export class AuxRuntime {
679
1244
  const bot = this._compiledState[id];
680
1245
  if (bot) {
681
1246
  removeFromContext(this._globalContext, [bot.script]);
1247
+ for (let breakpoint of bot.breakpoints) {
1248
+ this._interpreter.removeBreakpointById(breakpoint.id);
1249
+ this._breakpoints.delete(breakpoint.id);
1250
+ }
682
1251
  }
683
1252
  removedBots.push(bot);
684
1253
  delete this._compiledState[id];
@@ -800,6 +1369,25 @@ export class AuxRuntime {
800
1369
  const compiledValue = compiled.values[tag];
801
1370
  partial.values[tag] = convertToCopiableValue(hasValue(compiledValue) ? compiledValue : null);
802
1371
  }
1372
+ for (let breakpoint of compiled.breakpoints) {
1373
+ if (updatedTags.has(breakpoint.tag)) {
1374
+ // Update the breakpoint
1375
+ const func = compiled.listeners[breakpoint.tag];
1376
+ if (func) {
1377
+ this._compiler.setBreakpoint({
1378
+ id: breakpoint.id,
1379
+ func: func,
1380
+ interpreter: this._interpreter,
1381
+ lineNumber: breakpoint.lineNumber,
1382
+ columnNumber: breakpoint.columnNumber,
1383
+ states: breakpoint.states,
1384
+ });
1385
+ }
1386
+ else {
1387
+ this._interpreter.removeBreakpointById(breakpoint.id);
1388
+ }
1389
+ }
1390
+ }
803
1391
  if (u.signatures) {
804
1392
  if (!compiled.signatures) {
805
1393
  compiled.signatures = {};
@@ -829,6 +1417,12 @@ export class AuxRuntime {
829
1417
  notifyChange() {
830
1418
  if (!this._batchPending && this._autoBatch) {
831
1419
  this._batchPending = true;
1420
+ if (this.canTriggerBreakpoint) {
1421
+ this._scheduleJob('notifyChange', () => {
1422
+ this._processBatch();
1423
+ });
1424
+ return;
1425
+ }
832
1426
  queueMicrotask(() => {
833
1427
  this._processBatch();
834
1428
  });
@@ -901,12 +1495,22 @@ export class AuxRuntime {
901
1495
  }
902
1496
  }
903
1497
  _batchScriptResults(callback, batch, resetEnergy) {
904
- const results = this._calculateScriptResults(callback, resetEnergy);
1498
+ const result = this._calculateScriptResults(callback, resetEnergy);
1499
+ if (isRuntimePromise(result)) {
1500
+ return markAsRuntimePromise(result.then((results) => {
1501
+ if (batch) {
1502
+ this._actionBatch.push(...results.actions);
1503
+ this.notifyChange();
1504
+ }
1505
+ this._errorBatch.push(...results.errors);
1506
+ return results;
1507
+ }));
1508
+ }
905
1509
  if (batch) {
906
- this._actionBatch.push(...results.actions);
1510
+ this._actionBatch.push(...result.actions);
907
1511
  }
908
- this._errorBatch.push(...results.errors);
909
- return results;
1512
+ this._errorBatch.push(...result.errors);
1513
+ return result;
910
1514
  }
911
1515
  _calculateScriptResults(callback, resetEnergy) {
912
1516
  this._globalContext.playerBot = this.userBot;
@@ -914,6 +1518,17 @@ export class AuxRuntime {
914
1518
  this._globalContext.energy = DEFAULT_ENERGY;
915
1519
  }
916
1520
  const result = callback();
1521
+ if (isRuntimePromise(result)) {
1522
+ return markAsRuntimePromise(result.then((results) => {
1523
+ const actions = this._processUnbatchedActions();
1524
+ const errors = this._processUnbatchedErrors();
1525
+ return {
1526
+ result: results,
1527
+ actions: actions,
1528
+ errors: errors,
1529
+ };
1530
+ }));
1531
+ }
917
1532
  const actions = this._processUnbatchedActions();
918
1533
  const errors = this._processUnbatchedErrors();
919
1534
  return {
@@ -994,6 +1609,7 @@ export class AuxRuntime {
994
1609
  script: null,
995
1610
  originalTagEditValues: {},
996
1611
  originalTagMaskEditValues: {},
1612
+ breakpoints: [],
997
1613
  };
998
1614
  if (BOT_SPACE_TAG in bot) {
999
1615
  compiledBot.space = bot.space;
@@ -1211,7 +1827,16 @@ export class AuxRuntime {
1211
1827
  delete bot.originalTagEditValues[tag];
1212
1828
  }
1213
1829
  if (hasValue(tagValue)) {
1214
- bot.tags[tag] = tagValue;
1830
+ if (this._newBots.has(bot.id) &&
1831
+ (tagValue instanceof DateTime ||
1832
+ tagValue instanceof Vector2 ||
1833
+ tagValue instanceof Vector3 ||
1834
+ tagValue instanceof Rotation)) {
1835
+ bot.tags[tag] = convertToCopiableValue(tagValue);
1836
+ }
1837
+ else {
1838
+ bot.tags[tag] = tagValue;
1839
+ }
1215
1840
  }
1216
1841
  else {
1217
1842
  delete bot.tags[tag];
@@ -1315,12 +1940,22 @@ export class AuxRuntime {
1315
1940
  diagnosticFunctionName = tag;
1316
1941
  fileName = `${bot.id}.${diagnosticFunctionName}`;
1317
1942
  }
1943
+ const constants = Object.assign(Object.assign({}, this._library.api), { tagName: tag, globalThis: this._globalObject });
1944
+ const specifics = Object.assign({}, this._library.tagSpecificApi);
1945
+ if (this._interpreter) {
1946
+ delete constants.globalThis;
1947
+ // if (this.canTriggerBreakpoint) {
1948
+ Object.assign(constants, this._interpretedApi);
1949
+ Object.assign(specifics, this._interpretedTagSpecificApi);
1950
+ // }
1951
+ }
1318
1952
  const func = this._compiler.compile(script, {
1319
1953
  // TODO: Support all the weird features
1320
1954
  functionName: functionName,
1321
1955
  diagnosticFunctionName: diagnosticFunctionName,
1322
1956
  fileName: fileName,
1323
1957
  forceSync: this._forceSyncScripts,
1958
+ interpreter: this._interpreter,
1324
1959
  context: {
1325
1960
  bot,
1326
1961
  tag,
@@ -1335,8 +1970,8 @@ export class AuxRuntime {
1335
1970
  const data = this._handleError(err, ctx.bot, ctx.tag);
1336
1971
  throw data;
1337
1972
  },
1338
- constants: Object.assign(Object.assign({}, this._library.api), { tagName: tag, globalThis: this._globalObject }),
1339
- variables: Object.assign(Object.assign({}, this._library.tagSpecificApi), { this: (ctx) => (ctx.bot ? ctx.bot.script : null), thisBot: (ctx) => (ctx.bot ? ctx.bot.script : null), bot: (ctx) => (ctx.bot ? ctx.bot.script : null), tags: (ctx) => (ctx.bot ? ctx.bot.script.tags : null), raw: (ctx) => (ctx.bot ? ctx.bot.script.raw : null), masks: (ctx) => (ctx.bot ? ctx.bot.script.masks : null), creatorBot: (ctx) => ctx.creator, configBot: () => this.context.playerBot, links: (ctx) => (ctx.bot ? ctx.bot.script.links : null) }),
1973
+ constants: constants,
1974
+ variables: Object.assign(Object.assign({}, specifics), { this: (ctx) => (ctx.bot ? ctx.bot.script : null), thisBot: (ctx) => (ctx.bot ? ctx.bot.script : null), bot: (ctx) => (ctx.bot ? ctx.bot.script : null), tags: (ctx) => (ctx.bot ? ctx.bot.script.tags : null), raw: (ctx) => (ctx.bot ? ctx.bot.script.raw : null), masks: (ctx) => (ctx.bot ? ctx.bot.script.masks : null), creatorBot: (ctx) => ctx.creator, configBot: () => this.context.playerBot, links: (ctx) => (ctx.bot ? ctx.bot.script.links : null) }),
1340
1975
  arguments: [['that', 'data']],
1341
1976
  });
1342
1977
  if (hasValue(bot)) {
@@ -1477,5 +2112,228 @@ export class AuxRuntime {
1477
2112
  }
1478
2113
  return list;
1479
2114
  }
2115
+ setBreakpoint(breakpoint) {
2116
+ const bot = this.currentState[breakpoint.botId];
2117
+ const breakpointIndex = bot.breakpoints.findIndex((b) => b.id === breakpoint.id);
2118
+ if (breakpointIndex >= 0) {
2119
+ bot.breakpoints[breakpointIndex] = breakpoint;
2120
+ }
2121
+ else {
2122
+ bot.breakpoints.push(breakpoint);
2123
+ }
2124
+ this._breakpoints.set(breakpoint.id, breakpoint);
2125
+ const func = bot.listeners[breakpoint.tag];
2126
+ if (func) {
2127
+ this._compiler.setBreakpoint({
2128
+ id: breakpoint.id,
2129
+ func: func,
2130
+ interpreter: this._interpreter,
2131
+ lineNumber: breakpoint.lineNumber,
2132
+ columnNumber: breakpoint.columnNumber,
2133
+ states: breakpoint.states,
2134
+ });
2135
+ }
2136
+ }
2137
+ removeBreakpoint(breakpointId) {
2138
+ const breakpoint = this._breakpoints.get(breakpointId);
2139
+ if (breakpoint) {
2140
+ this._breakpoints.delete(breakpointId);
2141
+ const bot = this.currentState[breakpoint.botId];
2142
+ const breakpointIndex = bot.breakpoints.findIndex((b) => b.id === breakpoint.id);
2143
+ if (breakpointIndex >= 0) {
2144
+ bot.breakpoints.splice(breakpointIndex, 1);
2145
+ }
2146
+ this._interpreter.removeBreakpointById(breakpoint.id);
2147
+ }
2148
+ }
2149
+ continueAfterStop(stopId, continuation) {
2150
+ const state = this._stopState;
2151
+ if (!state || state.stopId !== stopId) {
2152
+ return;
2153
+ }
2154
+ this._stopState = null;
2155
+ this._globalContext.actions.push(...state.actions);
2156
+ this._globalContext.errors.push(...state.errors);
2157
+ this._executeGenerator(state.resolve, state.reject, state.generator, continuation);
2158
+ // this._processGenerator(state.generator, continuation).then(state.resolve, state.reject);
2159
+ }
2160
+ _scheduleJob(queueName, job) {
2161
+ if (this._interpreter) {
2162
+ this._interpreter.realm.scope(() => {
2163
+ this._interpreter.agent.queueJob(queueName, () => {
2164
+ job();
2165
+ return Value.undefined;
2166
+ });
2167
+ });
2168
+ }
2169
+ }
2170
+ _scheduleJobQueueCheck() {
2171
+ if (this._interpreter) {
2172
+ // Increment the current job queue check count and save it.
2173
+ // This is used to short-circuit job queue checks if future checks are scheduled
2174
+ // before this one runs.
2175
+ this._jobQueueCheckCount++;
2176
+ const currentCheck = this._jobQueueCheckCount;
2177
+ this._jobQueueCheckPending = true;
2178
+ // Queue a microtask to fire before the current task finishes
2179
+ queueMicrotask(() => {
2180
+ // Short circuit if another check has been scheduled.
2181
+ if (this._jobQueueCheckCount !== currentCheck) {
2182
+ return;
2183
+ }
2184
+ // Queue another microtask to ensure that the job queue gets processed
2185
+ // after all current microtasks are executed.
2186
+ // This allows _scheduleJobQueueCheck() to be scheduled before other microtasks are queued.
2187
+ queueMicrotask(() => {
2188
+ // Short circuit if another check has been scheduled.
2189
+ if (this._jobQueueCheckCount !== currentCheck ||
2190
+ this._interpreter.agent.jobQueue.length <= 0) {
2191
+ return;
2192
+ }
2193
+ this._processJobQueueNow();
2194
+ if (this._interpreter.agent.jobQueue.length <= 0) {
2195
+ // Check to see if any more jobs have been added after the job queue has been processed
2196
+ // and trigger another job queue check if they have.
2197
+ this._scheduleJobQueueCheck();
2198
+ }
2199
+ });
2200
+ });
2201
+ }
2202
+ }
2203
+ // private _processJobQueueMicrotask() {
2204
+ // queueMicrotask(() => {
2205
+ // this._processJobQueueNow();
2206
+ // });
2207
+ // }
2208
+ _processJobQueueNow() {
2209
+ const queueGen = this._interpreter.runJobQueue();
2210
+ while (true) {
2211
+ const next = queueGen.next();
2212
+ if (next.done) {
2213
+ break;
2214
+ }
2215
+ else {
2216
+ // TODO: Process breakpoint
2217
+ }
2218
+ }
2219
+ this._jobQueueCheckPending = false;
2220
+ }
2221
+ processGenerator(generator) {
2222
+ this._processGenerator(generator);
2223
+ }
2224
+ _processGenerator(generator, continuation) {
2225
+ return markAsRuntimePromise(new Promise((resolve, reject) => {
2226
+ this._executeGenerator(resolve, reject, generator, continuation);
2227
+ }));
2228
+ }
2229
+ _executeGenerator(resolve, reject, generator, continuation) {
2230
+ try {
2231
+ let result;
2232
+ while (true) {
2233
+ const next = generator.next(continuation);
2234
+ if (next.done === true) {
2235
+ result = next.value;
2236
+ break;
2237
+ }
2238
+ else {
2239
+ this._currentStopCount += 1;
2240
+ const actions = this._processUnbatchedActions();
2241
+ const errors = this._processUnbatchedErrors();
2242
+ const state = {
2243
+ stopId: this._currentStopCount,
2244
+ generator,
2245
+ resolve,
2246
+ reject,
2247
+ actions,
2248
+ errors,
2249
+ };
2250
+ this._stopState = state;
2251
+ let breakpoint = this._breakpoints.get(next.value.breakpoint.id);
2252
+ this._onRuntimeStop.next(Object.assign(Object.assign({}, next.value), { breakpoint, stopId: this._currentStopCount }));
2253
+ return;
2254
+ }
2255
+ }
2256
+ this._scheduleJobQueueCheck();
2257
+ resolve(result);
2258
+ }
2259
+ catch (err) {
2260
+ reject(err);
2261
+ }
2262
+ }
2263
+ }
2264
+ /**
2265
+ * Recursively maps each of the given library's functions using the given map function and returns a new library that contains the converted functions.
2266
+ * The returned object will contain the same enumerable properties as the original library except that its functions have been mapped.
2267
+ * @param library The library to map.
2268
+ * @param map The function to use for mapping library functions.
2269
+ */
2270
+ export function mapLibraryFunctions(library, map) {
2271
+ let newLibrary = Object.assign({}, library);
2272
+ newLibrary.api = mapFunctions(newLibrary.api, map);
2273
+ return newLibrary;
2274
+ }
2275
+ function mapFunctions(obj, map) {
2276
+ let newObj = Object.create(obj);
2277
+ assignFunctions(obj, newObj, map);
2278
+ return newObj;
2279
+ }
2280
+ function assignFunctions(obj, newObj, map) {
2281
+ let descriptors = Object.getOwnPropertyDescriptors(obj);
2282
+ for (let key in descriptors) {
2283
+ let descriptor = descriptors[key];
2284
+ if (descriptor.get || descriptor.set || !descriptor.enumerable) {
2285
+ continue;
2286
+ }
2287
+ const val = descriptor.value;
2288
+ if (typeof val === 'function') {
2289
+ let newFunc = (newObj[key] = map(val, key));
2290
+ if (newFunc) {
2291
+ assignFunctions(val, newFunc, map);
2292
+ }
2293
+ continue;
2294
+ }
2295
+ if (typeof val !== 'object' ||
2296
+ val === null ||
2297
+ Object.getPrototypeOf(val).constructor !== Object) {
2298
+ continue;
2299
+ }
2300
+ newObj[key] = mapFunctions(val, map);
2301
+ }
2302
+ }
2303
+ // function wrapGeneratorFunc<T>(
2304
+ // func: (...args: any[]) => T
2305
+ // ): (...args: any[]) => T {
2306
+ // return (...args: any[]) => {
2307
+ // let res = func(...args);
2308
+ // if (isGenerator(res)) {
2309
+ // return unwind(res);
2310
+ // }
2311
+ // return res;
2312
+ // };
2313
+ // }
2314
+ /**
2315
+ * Processes the given list of items in a sequential manner, calling the given function for each item.
2316
+ * @param list The list of items to process.
2317
+ * @param func The function that should be called for each item.
2318
+ */
2319
+ function processListOfMaybePromises(promise, list, func) {
2320
+ for (let item of list) {
2321
+ if (!isRuntimePromise(promise)) {
2322
+ const p = func(item);
2323
+ if (isRuntimePromise(p)) {
2324
+ promise = p;
2325
+ }
2326
+ }
2327
+ else {
2328
+ const copiedItem = item;
2329
+ promise = promise.then(() => {
2330
+ return func(copiedItem);
2331
+ });
2332
+ }
2333
+ }
2334
+ if (isPromise(promise)) {
2335
+ return markAsRuntimePromise(promise);
2336
+ }
2337
+ return promise;
1480
2338
  }
1481
2339
  //# sourceMappingURL=AuxRuntime.js.map