@naanlang/naan 1.3.2 → 1.4.1

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 (56) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +1 -1
  3. package/bin/index.js +25 -15
  4. package/dist/naan.min.js +5 -5
  5. package/frameworks/browser/sworker.js +23 -23
  6. package/frameworks/browser/terminals.nlg +26 -11
  7. package/frameworks/browser/ws_client.nlg +1 -1
  8. package/frameworks/client/psm_client.nlg +3 -1
  9. package/frameworks/client/relaycon.nlg +3 -2
  10. package/frameworks/common/common.nlg +5 -2
  11. package/frameworks/common/preferences.nlg +1 -1
  12. package/frameworks/node/apiserver.nlg +3 -3
  13. package/frameworks/node/filesystem.nlg +5 -4
  14. package/frameworks/node/psm_server.nlg +1 -1
  15. package/frameworks/node/shell.nlg +134 -0
  16. package/frameworks/node/worker.nlg +104 -46
  17. package/frameworks/project/build.nlg +1 -2
  18. package/frameworks/project/jszip.js +0 -0
  19. package/frameworks/project/projects.nlg +1 -1
  20. package/frameworks/running/debugnub.nlg +102 -12
  21. package/frameworks/running/debugutil.nlg +30 -13
  22. package/frameworks/running/executors.nlg +64 -28
  23. package/frameworks/running/running.nlg +85 -3
  24. package/frameworks/running/sourcecode.nlg +3 -1
  25. package/frameworks/running/taskexec.nlg +24 -4
  26. package/frameworks/storage/dbt_pouch.nlg +30 -17
  27. package/frameworks/storage/file_manager.nlg +1 -1
  28. package/frameworks/storage/psm.nlg +11 -1
  29. package/frameworks/storage/psm_dbtables.nlg +21 -22
  30. package/frameworks/storage/resources.nlg +12 -4
  31. package/frameworks/storage/storage.nlg +2 -2
  32. package/lib/browser/env_web.js +6 -6
  33. package/lib/browser/env_webworker.js +2 -0
  34. package/lib/core/naanlib.js +5 -5
  35. package/lib/env_nodeworker.js +2 -0
  36. package/package.json +1 -1
  37. package/plugins/gitClient/gitClient.nlg +3 -3
  38. package/plugins/gitClient/gitutils.nlg +2 -2
  39. package/plugins/nodeLib/node_https.nlg +2 -2
  40. package/plugins/openSearch/openSearch.nlg +2 -2
  41. package/plugins/serviceAws/lambda_naan_control.nlg +3 -3
  42. package/plugins/serviceAws/psm_aws.nlg +4 -2
  43. package/plugins/serviceAws/serviceAws.nlg +1 -1
  44. package/plugins/serviceGC/gc_api.nlg +5 -5
  45. package/plugins/serviceGitHub/gitops.nlg +4 -3
  46. package/plugins/serviceGitHub/psm_github.nlg +1 -1
  47. package/plugins/serviceGitHub/serviceGitHub.nlg +1 -1
  48. package/plugins/serviceGitLab/gitops.nlg +2 -1
  49. package/plugins/serviceGitLab/psm_gitlab.nlg +2 -2
  50. package/plugins/serviceGitLab/serviceGitLab.nlg +1 -1
  51. package/plugins/serviceYC/yc_vm.nlg +1 -1
  52. package/test/harness.nlg +9 -9
  53. package/test/test_01_core.nlg +24 -2
  54. package/test/test_02_context.nlg +2 -2
  55. package/test/test_07_lingo.nlg +3 -3
  56. package/plugins/serviceGC/russian_trusted_root_ca_pem.crt +0 -33
@@ -10,6 +10,13 @@
10
10
  *
11
11
  */
12
12
 
13
+ /*
14
+ * globals
15
+ *
16
+ */
17
+
18
+ gWorkers;
19
+
13
20
 
14
21
  /*
15
22
  * workCurrent
@@ -19,8 +26,8 @@
19
26
  */
20
27
 
21
28
  closure workCurrent(workco, workerID, startup, local current) {
22
- global()
23
- current = new(object, this)
29
+ global(js)
30
+ current = require("../running/executors.nlg").ExecutorBase(workco, workerID, startup.name)
24
31
  current.workerID = workerID
25
32
  current.name = startup.name
26
33
  current.links = []
@@ -94,6 +101,7 @@ closure workCurrent(workco, workerID, startup, local current) {
94
101
  function ONmessageOut(data) {
95
102
  if data._guid
96
103
  return // already replied
104
+ current.execReceived(data)
97
105
  sendAll({
98
106
  id: "targetout",
99
107
  data: data
@@ -153,7 +161,17 @@ closure workCurrent(workco, workerID, startup, local current) {
153
161
  if current.links.length == 0
154
162
  current.host.Detach(current.termif) // attached while one link is active
155
163
  }
156
-
164
+
165
+ //
166
+ // target.PostMessage
167
+ //
168
+ // Post a message to the main thread.
169
+ //
170
+ current.PostMessage = function PostMessage(data) {
171
+ js.t.DispatchMessage(data)
172
+ list(false, { posted: true })
173
+ }
174
+
157
175
  //
158
176
  // msgin
159
177
  //
@@ -188,6 +206,18 @@ closure workCurrent(workco, workerID, startup, local current) {
188
206
  };
189
207
 
190
208
 
209
+ /*
210
+ * WorkerConnect
211
+ *
212
+ * Return the existing web worker for a workerGUID, or false if it does not exist.
213
+ *
214
+ */
215
+
216
+ function WorkerConnect(workerGUID) {
217
+ gWorkers[workerGUID]
218
+ }
219
+
220
+
191
221
  /*
192
222
  * workMainProxy
193
223
  *
@@ -270,18 +300,19 @@ closure WorkerToMain(local nideRunning, track) {
270
300
  *
271
301
  */
272
302
 
273
- closure workThread(workco, workerID, startup, local worker, options, subChannel, deathWatcher) {
274
- global(threads, JSpath)
275
- worker = new(object, this)
303
+ closure workThread(workco, workerID, startup, guid
304
+ local worker, options, subChannel, deathWatcher) {
305
+ global(js, threads, JSpath)
306
+ worker = require("../running/executors.nlg").ExecutorBase(workco, workerID, startup.name)
276
307
  worker.name = startup.name
277
308
  worker.workerID = workerID
278
309
  worker.links = []
279
- worker.guid = UUID()
310
+ worker.guid = guid || UUID()
280
311
 
281
312
  // create our worker thread
282
313
 
283
314
  // options = { execArgv: ["--inspect-brk"] } // uncomment for NodeJS debugging
284
- worker.thread = xnew(threads.Worker, JSpath.resolve(js.d, "node_worker.js"), options)
315
+ worker.thread = xnew(threads.Worker, JSpath.resolve(js.d, "lib/node_worker.js"), options)
285
316
  subChannel = xnew(threads.MessageChannel)
286
317
  worker.thread.postMessage({ hereIsYourPort: subChannel.port1 }, [subChannel.port1])
287
318
  worker.msgport = subChannel.port2
@@ -346,6 +377,8 @@ closure workThread(workco, workerID, startup, local worker, options, subChannel,
346
377
  state: false // resume state, if we have any
347
378
  altcmd: false
348
379
  dirpath: js.d
380
+ workerID: workerID
381
+ workerGUID: worker.guid
349
382
  }
350
383
  if startup.initcmds
351
384
  startmsg.altcmd = startup.initcmds.concat("\n")
@@ -364,6 +397,8 @@ closure workThread(workco, workerID, startup, local worker, options, subChannel,
364
397
  else {
365
398
  if msg.id == "status"
366
399
  worker.lastStatus = milliseconds()
400
+ else if msg.id == "targetout"
401
+ worker.execReceived(msg.data)
367
402
  sendAll(msg) } // default is just return message to the client
368
403
  })
369
404
 
@@ -401,6 +436,19 @@ closure workThread(workco, workerID, startup, local worker, options, subChannel,
401
436
  removeLink(link)
402
437
  }
403
438
 
439
+ //
440
+ // PostMessage
441
+ //
442
+ // Post a message to the main thread.
443
+ //
444
+ worker.PostMessage = function PostMessage(data) {
445
+ worker.msgport.postMessage({ // send data to worker
446
+ id: "targetin",
447
+ data: data
448
+ })
449
+ list(false, { posted: true })
450
+ }
451
+
404
452
  //
405
453
  // msgin
406
454
  //
@@ -498,7 +546,7 @@ closure workLink(workco, conn, worker, sender, local link) {
498
546
  */
499
547
 
500
548
  closure workController(api, local workco) {
501
- global()
549
+ global(gWorkers)
502
550
  workco = new(object, this)
503
551
  workco.serverID = "Workers" // our serverID, used for communications
504
552
  workco.workers = { } // dictionary of workers by workerID
@@ -559,12 +607,47 @@ closure workController(api, local workco) {
559
607
  workco.workers[workerID] = undefined // it's like this worker has never been
560
608
  }
561
609
 
562
- //
610
+ // spawn
611
+ //
612
+ // Spawn a new worker with the specified configuration dictionary and optional GUID.
613
+ //
614
+ workco.spawn = closure spawn(workerID, config, guid, local worker) {
615
+ if !dictionary(gWorkers)
616
+ gWorkers = {}
617
+ worker = workco.workers[workerID]
618
+ if !worker { // create worker if needed
619
+ if workerID == "NideServer"
620
+ worker = workco.current = workCurrent(workco, workerID, config)
621
+ else
622
+ worker = workThread(workco, workerID, config, guid)
623
+ workco.uworkers[worker.guid] = worker
624
+ workco.workers[workerID] = worker
625
+ gWorkers[worker.guid] = worker }
626
+ if workerID == "NideServer"
627
+ workco.current.vitalUpdate({
628
+ id: "workerlist", // send the initial list of workers
629
+ workers: let(workers, workerID, worker) {
630
+ workers = { }
631
+ for `(workerID, worker) in workco.workers
632
+ workers[workerID] = {
633
+ name: worker.name
634
+ }
635
+ workers
636
+ }()
637
+ })
638
+ else {
639
+ worker.vitalWatch(termination)
640
+ workco.current.vitalUpdate({
641
+ id: "spawned", // note a new worker thread
642
+ name: config.name
643
+ workerID: workerID
644
+ }) }
645
+ }
646
+
563
647
  // wsReceive
564
648
  //
565
649
  // Process a message from the websocket API.
566
650
  //
567
-
568
651
  workco.wsReceive = function wsReceive(message, conn, local worker, link, error) {
569
652
  if !message.workerID
570
653
  error = Error("workerID required", message.workerOp)
@@ -576,50 +659,25 @@ closure workController(api, local workco) {
576
659
  if worker && message.payload {
577
660
  if !link
578
661
  makeLink(message, conn) // make sure we have a link for responses
579
- worker.msgin(message.payload) // send message to worker
580
- return } }
662
+ worker.msgin(message.payload) } // send message to worker
663
+ return }
581
664
  else if message.workerOp == "echo" {
582
665
  if worker && message.payload {
583
666
  if !link
584
667
  makeLink(message, conn) // make sure we have a link for responses
585
- worker.echo(message.payload, link) // echo message to other links
586
- return } }
668
+ worker.echo(message.payload, link) } // echo message to other links
669
+ return }
587
670
  else if message.workerOp == "spawn" {
588
- if !worker { // create worker if needed
589
- if message.workerID == "NideServer"
590
- worker = workco.current = workCurrent(workco, message.workerID, message.payload)
591
- else
592
- worker = workThread(workco, message.workerID, message.payload)
593
- workco.uworkers[worker.guid] = worker
594
- workco.workers[message.workerID] = worker }
671
+ spawn(message.workerID, message.payload, message.workerGUID)
595
672
  if !link
596
673
  makeLink(message, conn) // make sure we have a link for responses
597
- if message.workerID == "NideServer"
598
- workco.current.vitalUpdate({
599
- id: "workerlist", // send the initial list of workers
600
- workers: let(workers, workerID, worker) {
601
- workers = { }
602
- for `(workerID, worker) in workco.workers
603
- workers[workerID] = {
604
- name: worker.name
605
- }
606
- workers
607
- }()
608
- })
609
- else {
610
- worker.vitalWatch(termination)
611
- workco.current.vitalUpdate({
612
- id: "spawned", // note a new worker thread
613
- name: message.payload.name
614
- workerID: message.workerID
615
- }) }
616
674
  return }
617
675
  else if message.workerOp == "terminate" {
618
676
  if worker {
619
677
  if !link
620
678
  makeLink(message, conn) // make sure we have a link for responses
621
- worker.terminate() // echo message to other links
622
- return } }
679
+ worker.terminate() } // echo message to other links
680
+ return }
623
681
  error = Error("invalid parameters", message.workerOp, message.workerID)
624
682
  }
625
683
  ErrorDebuglog("workController.wsReceive error:", error)
@@ -663,13 +721,13 @@ closure workController(api, local workco) {
663
721
  */
664
722
 
665
723
  function workInit(local manifest) {
666
- manifest = `(workCurrent, workMainProxy, WorkerToMain, workThread, workLink, workController,
667
- workInit)
668
-
724
+ manifest = `(workCurrent, WorkerConnect, workMainProxy, WorkerToMain, workThread, workLink,
725
+ workController, workInit)
669
726
  Naan.module.build(module.id, "worker", function(modobj, compobj) {
670
727
  require("./node.nlg")
671
728
  compobj.manifest = manifest
672
729
  modobj.exports.WorkerController = workController
730
+ modobj.exports.WorkerConnect = WorkerConnect
673
731
  modobj.exports.WorkerToMain = WorkerToMain
674
732
  })
675
733
  }();
@@ -368,7 +368,7 @@ closure Builder(rules, operation, fs, srcpath, destpath, track, local build, gro
368
368
  // for each file. The result is a standard (error, data) tuple.
369
369
 
370
370
  function zip1(files, options, local libzip, ziparc, file, result) {
371
- libzip = require("frameworks/project/jszip.nlg").JSZip()
371
+ libzip = require("naanlib:frameworks/project/jszip.nlg").JSZip()
372
372
  if !libzip
373
373
  return (list(Error("Build requires zip but it's not available")))
374
374
  ziparc = libzip.create()
@@ -1067,7 +1067,6 @@ closure Builder(rules, operation, fs, srcpath, destpath, track, local build, gro
1067
1067
  //
1068
1068
  function writeCatenate(writepath,
1069
1069
  local template, entry, content, catsub, dozip, docat, fsoptions, zipmap, error, result) {
1070
- debuglog("writeCatenate", writepath)
1071
1070
  template = build.templates[writepath] // optional in some cases ### should warn in others
1072
1071
  catsub = { }
1073
1072
  for entry in catenates[writepath] { // error check and substitution build
File without changes
@@ -296,7 +296,7 @@ closure projConnector(projman, projtype, local connector, watch) {
296
296
  *
297
297
  * Nide.proj/
298
298
  * nide_cliser.cfg - JSON definition of the project (see below)
299
- * NaanIDE_version.txt - [default] substitution file defining 1.3.2+1 etc.
299
+ * NaanIDE_version.txt - [default] substitution file defining 1.4.1+1 etc.
300
300
  * NaanIDE_version_builds.txt - [default] contains current build number as decimal string
301
301
  * build/ - [optional] default build output location
302
302
  * NaanIDE.lic - [optional] defines Zulch Laboratories, Inc. and other license info
@@ -33,6 +33,9 @@ closure DebugNub(local nub, debug, paused) {
33
33
  nub.codemgr = CodeManager()
34
34
  nub.exenable = true
35
35
  nub.watches = []
36
+ nub.contIDs = new(weakmap)
37
+ nub.stacks = { }
38
+ nub.usage = { }
36
39
 
37
40
  // debugDepth
38
41
  // Return the recursive debugging depth as an integer.
@@ -80,7 +83,7 @@ closure DebugNub(local nub, debug, paused) {
80
83
  for frame in nub.frames
81
84
  if procedure(frame)
82
85
  break
83
- `(procdef, task) = nub.procTask(frame)
86
+ `(procdef, task) = debug.frameProcTask(frame)
84
87
  }
85
88
  if !procdef
86
89
  return (false)
@@ -396,14 +399,75 @@ closure DebugNub(local nub, debug, paused) {
396
399
  output.push(breakInfo(bpid))
397
400
  output
398
401
  }
402
+
403
+ // procLoc
404
+ //
405
+ // Get the location of a procdef.
406
+
407
+ nub.procLoc = function procLoc(procdef, task, local comp, position) {
408
+ if !task
409
+ task = rrrest(procdef)
410
+ comp = nub.codemgr.procComponent(procdef)
411
+ position = comp.textpos(procdef, task)
412
+ {
413
+ modname: comp.modname
414
+ compname: comp.compname
415
+ first: position.first
416
+ last: position.last
417
+ line: position.line
418
+ }
419
+ }
420
+
421
+ // getContID
422
+ //
423
+ // Get the contID for a continuation.
424
+
425
+ nub.getContID = function getContID(cont, local contID, frames) {
426
+ contID = nub.contIDs[cont]
427
+ if !contID
428
+ nub.contIDs[cont] = contID = UUID()
429
+ frames = cont.stacktrace().toarray
430
+ if frames.slice(-1).0 == `interrupt
431
+ frames.pop()
432
+ nub.stacks[contID] = frames
433
+ contID
434
+ }
435
+
436
+ // contGC
437
+ //
438
+ // Remove any continuations that are not in the specified array.
439
+
440
+ nub.contGC = function contGC(contIDs, local contID) {
441
+ contIDs = contIDs.concat(nub.usage.*.toarray) // keep preserved ids
442
+ for contID in nub.stacks
443
+ if contIDs.indexOf(contID) < 0
444
+ nub.stacks[contID] = undefined
445
+ }
446
+
447
+ // usingContID
448
+ //
449
+ // Mark that the contID is being used.
450
+ //
451
+ nub.usingContID = function usingContID(contID, usage) {
452
+ if nub.usage[contID]
453
+ nub.usage[contID] += usage
454
+ else if usage > 0
455
+ nub.usage[contID] = usage
456
+ if nub.usage[contID] == 0
457
+ nub.usage[contID] = undefined
458
+ }
399
459
 
400
460
  // callStack
401
461
  //
402
- // List our callers as of the last entry.
462
+ // List our callers as of the last entry in the optional frames or current debugger stack.
403
463
 
404
- nub.callStack = function callStack(local output, frame, type, record) {
464
+ nub.callStack = function callStack(contID, local frames, output, frame, type, record) {
405
465
  output = []
406
- for frame in nub.frames {
466
+ if contID
467
+ frames = nub.stacks[contID]
468
+ else
469
+ frames = nub.frames
470
+ for frame in frames {
407
471
  record = {
408
472
  type: frame.0.tostring // e.g. "function"
409
473
  }
@@ -425,8 +489,12 @@ closure DebugNub(local nub, debug, paused) {
425
489
  //
426
490
  // Return the nth stack frame in the list returned by callStack above.
427
491
 
428
- nub.nthFrame = function nthFrame(nth, local frame) {
429
- for frame in nub.frames
492
+ nub.nthFrame = function nthFrame(nth, contID, local frames, frame) {
493
+ if contID
494
+ frames = nub.stacks[contID]
495
+ else
496
+ frames = nub.frames
497
+ for frame in frames
430
498
  if procedure(frame) || frame.0.tostring == "interrupt" {
431
499
  if nth-- == 0
432
500
  return (frame)
@@ -469,14 +537,15 @@ closure DebugNub(local nub, debug, paused) {
469
537
 
470
538
  // evalWatchesInFrame
471
539
  //
472
- // Parse and evaluate our watchpoints, optionally in the context of the nth frame. Each entry
473
- // in the returned array is for a watchpoint, comprising a tuple: `(error, expression, evaluated)
540
+ // Parse and evaluate our watchpoints, optionally in the context of the nth frame of the
541
+ // specified continuation or the current debugger stack. Each entry in the returned array is for
542
+ // a watchpoint, comprising a tuple: `(error, expression, evaluated).
474
543
 
475
- nub.evalWatchesInFrame = function evalWatchesInFrame(nth,
544
+ nub.evalWatchesInFrame = function evalWatchesInFrame(nth, contID,
476
545
  local frame, locals, ns, mod, gohome, texts, watch, exprs, error, expr)
477
546
  {
478
547
  if integer(nth) {
479
- frame = nthFrame(nth)
548
+ frame = nthFrame(nth, contID)
480
549
  locals = localist(frame)
481
550
  ns = frame.3.1.namespace
482
551
  if ns !== nsactive().0 {
@@ -506,8 +575,29 @@ closure DebugNub(local nub, debug, paused) {
506
575
  //
507
576
  // Return procedure and task from a frame, as a `(procdef, task) tuple.
508
577
 
509
- nub.procTask = function procTask(frame) {
510
- debug.frameProcTask(frame)
578
+ nub.procTask = function procTask(frame, contID, local frames, ftrav, procdef, bodydef) {
579
+ if contID
580
+ frames = new(nub.stacks[contID])
581
+ else
582
+ frames = new(debug.frames)
583
+ loop {
584
+ if frames.length == 0
585
+ break
586
+ ftrav = frames.shift()
587
+ if ftrav eq frame
588
+ frame = false // can now stop on our desired procedure
589
+ if procedure(ftrav) {
590
+ if !frame {
591
+ procdef = ftrav.3 // first procedure definition starting with desired frame
592
+ if !bodydef
593
+ bodydef = procdef // use procdef as body if no body frame found
594
+ break }
595
+ bodydef = false } // any previously-found body applies to wrong procedure
596
+ else if ftrav.0 == `body || ftrav.0 == `loop {
597
+ if !bodydef
598
+ bodydef = ftrav.2 } } // use first body found before desired procedure
599
+ if procdef
600
+ list(procdef, bodydef) // found valid location
511
601
  }
512
602
 
513
603
  // lastStepValue
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2021 by Richard C. Zulch
9
+ * Copyright (c) 2021-2024 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
@@ -260,24 +260,33 @@ closure DebugRemote(commander, local remoter, here, there, library) {
260
260
  here.breakInfo = function breakInfo(bpid) {
261
261
  libBreakInfo(bpid)
262
262
  }
263
+
264
+ // usingContID
265
+ //
266
+ // Mark that the contID is being used.
267
+ //
268
+ here.usingContID = function usingContID(contID, usage) {
269
+ debugNub = car(compress("debugNub"))
270
+ debugNub.usingContID(contID, usage)
271
+ }
263
272
 
264
273
  // callstack
265
274
  //
266
- // Report current callstack.
275
+ // Report the specified fiber callstack or current debugger stack.
267
276
  //
268
- here.callStack = function callStack(local debugNub) {
277
+ here.callStack = function callStack(contID, local debugNub) {
269
278
  debugNub = car(compress("debugNub"))
270
- debugNub.callStack()
279
+ debugNub.callStack(contID)
271
280
  }
272
281
 
273
282
  // frameinfo
274
283
  //
275
- // Report information about the nth frame in the callStack.
284
+ // Report information about the nth frame in a fiber callstack or the current debugger stack.
276
285
  //
277
- here.frameinfo = function frameinfo(nth, local debugNub, frame, proctask, comp, position) {
286
+ here.frameinfo = function frameinfo(nth, contID, local debugNub, frame, proctask, comp, position) {
278
287
  debugNub = car(compress("debugNub"))
279
- frame = debugNub.nthFrame(nth)
280
- proctask = debugNub.procTask(frame)
288
+ frame = debugNub.nthFrame(nth, contID)
289
+ proctask = debugNub.procTask(frame, contID)
281
290
  comp = debugNub.codemgr.procComponent(proctask.0)
282
291
  position = comp.textpos(proctask.0, proctask.1)
283
292
  {
@@ -302,11 +311,11 @@ closure DebugRemote(commander, local remoter, here, there, library) {
302
311
  // The optional visible array is a preceding result of this function, where "visible=true"
303
312
  // can be applied to nested values to add recursive depth.
304
313
  //
305
- here.scopeinfo = function scopeinfo(nth, visible,
314
+ here.scopeinfo = function scopeinfo(nth, visible, contID
306
315
  local debugNub, frame, procsym, parent, proc, lex1, ex1, params, content, scope, level, level1)
307
316
  {
308
317
  debugNub = car(compress("debugNub"))
309
- frame = debugNub.nthFrame(nth)
318
+ frame = debugNub.nthFrame(nth, contID)
310
319
  procsym = frame.3.1
311
320
  parent = procsym@\.parent
312
321
  while parent {
@@ -370,11 +379,11 @@ closure DebugRemote(commander, local remoter, here, there, library) {
370
379
  // can be applied to nested values to add recursive depth. A stack frame index can be specified
371
380
  // to evaluate an expression in that context.
372
381
 
373
- here.watchInfo = function watchInfo(visible, nth,
382
+ here.watchInfo = function watchInfo(visible, nth, contID,
374
383
  local debugNub, values, content, watch, child1, error, value, level, expr)
375
384
  {
376
385
  debugNub = car(compress("debugNub"))
377
- values = debugNub.evalWatchesInFrame(nth)
386
+ values = debugNub.evalWatchesInFrame(nth, contID)
378
387
  visible = new(visible) // don't modify original
379
388
  content = []
380
389
  for watch in debugNub.watches {
@@ -417,8 +426,9 @@ closure DebugRemote(commander, local remoter, here, there, library) {
417
426
  //
418
427
  // List the current futures.
419
428
 
420
- here.futureslist = function futureslist(local debugNub, output, future, record, procsym) {
429
+ here.futureslist = closure futureslist(local debugNub, contIDs, output, future, record, procsym) {
421
430
  debugNub = car(compress("debugNub"))
431
+ contIDs = []
422
432
  output = []
423
433
  for future in futures() {
424
434
  if member(debugNub.pauser, future.waiting)
@@ -431,6 +441,7 @@ closure DebugRemote(commander, local remoter, here, there, library) {
431
441
  if procedure(future.execute) {
432
442
  procsym = future.execute.1
433
443
  record.execute = strcat(future.execute.0, space, procsym.namespace.tostring, "::", debugNub.procname(procsym))
444
+ record.execloc = debugNub.procLoc(future.execute)
434
445
  }
435
446
  else if future.execute
436
447
  record.execute = tostring(future.execute)
@@ -439,9 +450,15 @@ closure DebugRemote(commander, local remoter, here, there, library) {
439
450
  procsym = item.1
440
451
  strcat(item.0, space, procsym.namespace.tostring, "::", debugNub.procname(procsym))
441
452
  })
453
+ record.continuations = future.continuations.toarray.map(function(cont, local contID) {
454
+ contID = debugNub.getContID(cont)
455
+ contIDs.push(contID)
456
+ contID
457
+ })
442
458
  }
443
459
  output.push(record)
444
460
  }
461
+ debugNub.contGC(contIDs)
445
462
  output
446
463
  }
447
464