stone-lang 0.1.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.
Files changed (68) hide show
  1. package/README.md +52 -0
  2. package/StoneEngine.js +879 -0
  3. package/StoneEngineService.js +1727 -0
  4. package/adapters/FileSystemAdapter.js +230 -0
  5. package/adapters/OutputAdapter.js +208 -0
  6. package/adapters/index.js +6 -0
  7. package/cli/CLIOutputAdapter.js +196 -0
  8. package/cli/DaemonClient.js +349 -0
  9. package/cli/JSONOutputAdapter.js +135 -0
  10. package/cli/ReplSession.js +567 -0
  11. package/cli/ViewerServer.js +590 -0
  12. package/cli/commands/check.js +84 -0
  13. package/cli/commands/daemon.js +189 -0
  14. package/cli/commands/kill.js +66 -0
  15. package/cli/commands/package.js +713 -0
  16. package/cli/commands/ps.js +65 -0
  17. package/cli/commands/run.js +537 -0
  18. package/cli/entry.js +169 -0
  19. package/cli/index.js +14 -0
  20. package/cli/stonec.js +358 -0
  21. package/cli/test-compiler.js +181 -0
  22. package/cli/viewer/index.html +495 -0
  23. package/daemon/IPCServer.js +455 -0
  24. package/daemon/ProcessManager.js +327 -0
  25. package/daemon/ProcessRunner.js +307 -0
  26. package/daemon/daemon.js +398 -0
  27. package/daemon/index.js +16 -0
  28. package/frontend/analysis/index.js +5 -0
  29. package/frontend/analysis/livenessAnalyzer.js +568 -0
  30. package/frontend/analysis/treeShaker.js +265 -0
  31. package/frontend/index.js +20 -0
  32. package/frontend/parsing/astBuilder.js +2196 -0
  33. package/frontend/parsing/index.js +7 -0
  34. package/frontend/parsing/sonParser.js +592 -0
  35. package/frontend/parsing/stoneAstTypes.js +703 -0
  36. package/frontend/parsing/terminal-registry.js +435 -0
  37. package/frontend/parsing/tokenizer.js +692 -0
  38. package/frontend/type-checker/OverloadedFunctionType.js +43 -0
  39. package/frontend/type-checker/TypeEnvironment.js +165 -0
  40. package/frontend/type-checker/bidirectionalInference.js +149 -0
  41. package/frontend/type-checker/index.js +10 -0
  42. package/frontend/type-checker/moduleAnalysis.js +248 -0
  43. package/frontend/type-checker/operatorMappings.js +35 -0
  44. package/frontend/type-checker/overloadResolution.js +605 -0
  45. package/frontend/type-checker/typeChecker.js +452 -0
  46. package/frontend/type-checker/typeCompatibility.js +389 -0
  47. package/frontend/type-checker/visitors/controlFlow.js +483 -0
  48. package/frontend/type-checker/visitors/functions.js +604 -0
  49. package/frontend/type-checker/visitors/index.js +38 -0
  50. package/frontend/type-checker/visitors/literals.js +341 -0
  51. package/frontend/type-checker/visitors/modules.js +159 -0
  52. package/frontend/type-checker/visitors/operators.js +109 -0
  53. package/frontend/type-checker/visitors/statements.js +768 -0
  54. package/frontend/types/index.js +5 -0
  55. package/frontend/types/operatorMap.js +134 -0
  56. package/frontend/types/types.js +2046 -0
  57. package/frontend/utils/errorCollector.js +244 -0
  58. package/frontend/utils/index.js +5 -0
  59. package/frontend/utils/moduleResolver.js +479 -0
  60. package/package.json +50 -0
  61. package/packages/browserCache.js +359 -0
  62. package/packages/fetcher.js +236 -0
  63. package/packages/index.js +130 -0
  64. package/packages/lockfile.js +271 -0
  65. package/packages/manifest.js +291 -0
  66. package/packages/packageResolver.js +356 -0
  67. package/packages/resolver.js +310 -0
  68. package/packages/semver.js +635 -0
@@ -0,0 +1,435 @@
1
+ /**
2
+ * Terminal Registry
3
+ *
4
+ * Provides terminal handle class and constructor factories for Stone terminals.
5
+ * Terminals are first-class runtime objects that represent output channels
6
+ * (2D graphs, 3D scenes).
7
+ *
8
+ * Supports two modes:
9
+ * - Legacy: Direct executor.terminalsData mutation (backward compat)
10
+ * - Adapter: Stream via OutputAdapter (new CLI/daemon path)
11
+ */
12
+
13
+ import { StoneArray } from '../../backends/js-vm/stoneArray.js';
14
+
15
+ // ============================================================================
16
+ // STONEARRAY CONVERSION UTILITIES
17
+ // ============================================================================
18
+
19
+ /**
20
+ * Check if a value is a StoneArray
21
+ */
22
+ function isStoneArray(value) {
23
+ return value instanceof StoneArray || value?._type === 'StoneArray';
24
+ }
25
+
26
+ /**
27
+ * Convert a StoneArray to a plain JavaScript array.
28
+ * Uses the built-in toNested() method for proper conversion.
29
+ */
30
+ function stoneArrayToJS(arr) {
31
+ if (!isStoneArray(arr)) return arr;
32
+
33
+ // Use the built-in toNested() method if available (live StoneArray)
34
+ if (typeof arr.toNested === 'function') {
35
+ return arr.toNested();
36
+ }
37
+
38
+ // Fallback: handle raw data directly
39
+ const data = ArrayBuffer.isView(arr.data) ? Array.from(arr.data) : arr.data;
40
+
41
+ if (arr.rank === 1) {
42
+ return Array.isArray(data) ? data : Array.from(data);
43
+ }
44
+
45
+ if (arr.rank === 2) {
46
+ const [rows, cols] = arr.shape;
47
+ const result = [];
48
+ for (let i = 0; i < rows; i++) {
49
+ result.push(data.slice(i * cols, (i + 1) * cols));
50
+ }
51
+ return result;
52
+ }
53
+
54
+ return data;
55
+ }
56
+
57
+ /**
58
+ * Recursively convert all StoneArrays in an object to plain JS arrays.
59
+ * This ensures data is stored in a format that serializes correctly to JSON
60
+ * and can be used directly by Plotly without further conversion.
61
+ */
62
+ function deepConvertStoneArrays(obj) {
63
+ if (obj === null || obj === undefined) return obj;
64
+
65
+ // If it's a StoneArray, convert it
66
+ if (isStoneArray(obj)) {
67
+ return stoneArrayToJS(obj);
68
+ }
69
+
70
+ // If it's an array, recursively convert each element
71
+ if (Array.isArray(obj)) {
72
+ return obj.map(deepConvertStoneArrays);
73
+ }
74
+
75
+ // If it's an object, recursively convert each property
76
+ if (typeof obj === 'object') {
77
+ const result = {};
78
+ for (const key in obj) {
79
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
80
+ result[key] = deepConvertStoneArrays(obj[key]);
81
+ }
82
+ }
83
+ return result;
84
+ }
85
+
86
+ // Primitive values pass through unchanged
87
+ return obj;
88
+ }
89
+
90
+ /**
91
+ * TerminalHandle - Handle to a terminal instance
92
+ *
93
+ * Represents a reference to a terminal that can be used to send data
94
+ * via method calls: graph.add(data), graph.set(data), scene.add(obj), etc.
95
+ */
96
+ export class TerminalHandle {
97
+ /**
98
+ * @param {string} type - Terminal type ('console', 'graph2d', 'graph3d')
99
+ * @param {Object} config - Terminal configuration
100
+ * @param {string} id - Unique terminal ID
101
+ * @param {Object} context - Either { executor } (legacy) or { outputAdapter } (new)
102
+ */
103
+ constructor(type, config, id, context) {
104
+ this._type = 'TerminalHandle';
105
+ this.terminalType = type;
106
+ this.terminalId = id;
107
+ this.config = config || {};
108
+ this.ports = {}; // View port data (snapshots)
109
+
110
+ // Support both legacy executor mode and new adapter mode
111
+ if (context.outputAdapter) {
112
+ this.outputAdapter = context.outputAdapter;
113
+ this.executor = null;
114
+ // In adapter mode, ports are managed locally
115
+ this._initPorts();
116
+ } else if (context.executor) {
117
+ // Legacy mode - direct executor mutation
118
+ this.executor = context.executor;
119
+ this.outputAdapter = null;
120
+ } else {
121
+ throw new Error('TerminalHandle requires either executor or outputAdapter');
122
+ }
123
+ }
124
+
125
+ _initPorts() {
126
+ switch (this.terminalType) {
127
+ case 'graph2d':
128
+ this.ports.plots = [];
129
+ break;
130
+ case 'graph3d':
131
+ this.ports.objects = [];
132
+ break;
133
+ case 'console':
134
+ this.ports.lines = [];
135
+ break;
136
+ }
137
+ this.ports.config = { ...this.config };
138
+ }
139
+
140
+ /**
141
+ * Add data to the terminal's main port
142
+ * - graph2d: adds plot(s) to plots
143
+ * - graph3d: adds object(s) to objects
144
+ * - console: adds line(s) to lines
145
+ *
146
+ * If value is an array, adds each item. Otherwise adds the single item.
147
+ * StoneArrays are converted to plain JS arrays for proper JSON serialization.
148
+ */
149
+ add(value) {
150
+ // Convert StoneArrays to plain JS arrays before storing
151
+ const converted = deepConvertStoneArrays(value);
152
+ const items = Array.isArray(converted) ? converted : [converted];
153
+
154
+ if (this.outputAdapter) {
155
+ // New adapter mode - stream via adapter
156
+ this.outputAdapter.addToTerminal(this.terminalId, items);
157
+ // Also update local ports for consistency
158
+ this._addToLocalPorts(items);
159
+ } else {
160
+ // Legacy mode - direct mutation
161
+ const terminalData = this.executor.terminalsData[this.terminalId];
162
+ switch (this.terminalType) {
163
+ case 'graph2d':
164
+ terminalData.plots.push(...items);
165
+ this.ports.plots = [...terminalData.plots];
166
+ break;
167
+ case 'graph3d':
168
+ terminalData.objects.push(...items);
169
+ this.ports.objects = [...terminalData.objects];
170
+ break;
171
+ case 'console':
172
+ terminalData.lines.push(...items);
173
+ this.ports.lines = [...terminalData.lines];
174
+ break;
175
+ }
176
+ }
177
+ return this; // Enable chaining
178
+ }
179
+
180
+ _addToLocalPorts(items) {
181
+ switch (this.terminalType) {
182
+ case 'graph2d':
183
+ this.ports.plots.push(...items);
184
+ break;
185
+ case 'graph3d':
186
+ this.ports.objects.push(...items);
187
+ break;
188
+ case 'console':
189
+ this.ports.lines.push(...items);
190
+ break;
191
+ }
192
+ }
193
+
194
+ /**
195
+ * Set the terminal's main port data (replaces existing)
196
+ * - graph2d: sets plots array
197
+ * - graph3d: sets objects array
198
+ * - console: sets lines array
199
+ * StoneArrays are converted to plain JS arrays for proper JSON serialization.
200
+ */
201
+ set(value) {
202
+ // Convert StoneArrays to plain JS arrays before storing
203
+ const converted = deepConvertStoneArrays(value);
204
+ const arr = Array.isArray(converted) ? converted : [converted];
205
+
206
+ if (this.outputAdapter) {
207
+ // New adapter mode - stream via adapter
208
+ this.outputAdapter.setTerminal(this.terminalId, arr);
209
+ // Also update local ports for consistency
210
+ this._setLocalPorts(arr);
211
+ } else {
212
+ // Legacy mode - direct mutation
213
+ const terminalData = this.executor.terminalsData[this.terminalId];
214
+ switch (this.terminalType) {
215
+ case 'graph2d':
216
+ terminalData.plots = arr;
217
+ this.ports.plots = [...terminalData.plots];
218
+ break;
219
+ case 'graph3d':
220
+ terminalData.objects = arr;
221
+ this.ports.objects = [...terminalData.objects];
222
+ break;
223
+ case 'console':
224
+ terminalData.lines = arr;
225
+ this.ports.lines = [...terminalData.lines];
226
+ break;
227
+ }
228
+ }
229
+ return this;
230
+ }
231
+
232
+ _setLocalPorts(arr) {
233
+ switch (this.terminalType) {
234
+ case 'graph2d':
235
+ this.ports.plots = [...arr];
236
+ break;
237
+ case 'graph3d':
238
+ this.ports.objects = [...arr];
239
+ break;
240
+ case 'console':
241
+ this.ports.lines = [...arr];
242
+ break;
243
+ }
244
+ }
245
+
246
+ /**
247
+ * Clear all data from the terminal's main port
248
+ */
249
+ clear() {
250
+ if (this.outputAdapter) {
251
+ // New adapter mode - stream via adapter
252
+ this.outputAdapter.clearTerminal(this.terminalId);
253
+ // Also update local ports
254
+ this._clearLocalPorts();
255
+ } else {
256
+ // Legacy mode - direct mutation
257
+ const terminalData = this.executor.terminalsData[this.terminalId];
258
+ switch (this.terminalType) {
259
+ case 'graph2d':
260
+ terminalData.plots = [];
261
+ this.ports.plots = [];
262
+ break;
263
+ case 'graph3d':
264
+ terminalData.objects = [];
265
+ this.ports.objects = [];
266
+ break;
267
+ case 'console':
268
+ terminalData.lines = [];
269
+ this.ports.lines = [];
270
+ break;
271
+ }
272
+ }
273
+ return this;
274
+ }
275
+
276
+ _clearLocalPorts() {
277
+ switch (this.terminalType) {
278
+ case 'graph2d':
279
+ this.ports.plots = [];
280
+ break;
281
+ case 'graph3d':
282
+ this.ports.objects = [];
283
+ break;
284
+ case 'console':
285
+ this.ports.lines = [];
286
+ break;
287
+ }
288
+ }
289
+
290
+ // Custom serialization - exclude executor/adapter reference
291
+ toJSON() {
292
+ return {
293
+ _type: this._type,
294
+ terminalType: this.terminalType,
295
+ terminalId: this.terminalId,
296
+ config: this.config,
297
+ ports: this.ports
298
+ };
299
+ }
300
+ }
301
+
302
+ /**
303
+ * Create terminal constructor functions.
304
+ *
305
+ * Supports two modes:
306
+ * - Legacy: Pass executor object with terminalsData and terminalCounter
307
+ * - Adapter: Pass object with outputAdapter and terminalCounter
308
+ *
309
+ * @param {Object} context - Either executor (legacy) or { outputAdapter, terminalCounter } (new)
310
+ * @returns {Object} - Object with console_terminal, graph2d, graph3d functions
311
+ */
312
+ export function createTerminalConstructors(context) {
313
+ // Determine mode based on what's provided
314
+ // Check for both null and undefined to properly detect adapter mode
315
+ const isAdapterMode = context.outputAdapter != null;
316
+
317
+ // Get or create terminal counter
318
+ let counterRef;
319
+ if (isAdapterMode) {
320
+ // Adapter mode - counter passed in context or create new one
321
+ counterRef = { value: context.terminalCounter || 0 };
322
+ } else {
323
+ // Legacy mode - counter is on executor
324
+ counterRef = { get value() { return context.terminalCounter; }, set value(v) { context.terminalCounter = v; } };
325
+ }
326
+
327
+ const getNextId = (prefix) => {
328
+ const id = `${prefix}_${counterRef.value}`;
329
+ counterRef.value++;
330
+ return id;
331
+ };
332
+
333
+ return {
334
+ console_terminal: (config = {}) => {
335
+ const terminalId = getNextId('console');
336
+ const fullConfig = {
337
+ title: config.title || 'Console',
338
+ max_lines: config.max_lines || 200,
339
+ ...config
340
+ };
341
+
342
+ if (isAdapterMode) {
343
+ // New adapter mode - create via adapter
344
+ context.outputAdapter.createTerminal(terminalId, 'console', fullConfig);
345
+ return new TerminalHandle('console', fullConfig, terminalId, { outputAdapter: context.outputAdapter });
346
+ } else {
347
+ // Legacy mode - direct mutation
348
+ const handle = new TerminalHandle('console', fullConfig, terminalId, { executor: context });
349
+ context.terminalsData[terminalId] = {
350
+ type: 'console',
351
+ config: fullConfig,
352
+ lines: []
353
+ };
354
+ handle.ports = {
355
+ lines: [],
356
+ config: { ...fullConfig }
357
+ };
358
+ return handle;
359
+ }
360
+ },
361
+
362
+ graph2d: (config = {}) => {
363
+ const terminalId = getNextId('graph2d');
364
+ // Convert StoneArrays in config (e.g., axes.t.values) to plain JS arrays
365
+ const fullConfig = deepConvertStoneArrays({
366
+ title: config.title || 'Graph',
367
+ x_label: config.x_label || 'x',
368
+ y_label: config.y_label || 'y',
369
+ ...config
370
+ });
371
+
372
+ if (isAdapterMode) {
373
+ // New adapter mode - create via adapter
374
+ context.outputAdapter.createTerminal(terminalId, 'graph2d', fullConfig);
375
+ return new TerminalHandle('graph2d', fullConfig, terminalId, { outputAdapter: context.outputAdapter });
376
+ } else {
377
+ // Legacy mode - direct mutation
378
+ const handle = new TerminalHandle('graph2d', fullConfig, terminalId, { executor: context });
379
+ context.terminalsData[terminalId] = {
380
+ type: 'graph2d',
381
+ config: fullConfig,
382
+ plots: []
383
+ };
384
+ handle.ports = {
385
+ plots: [],
386
+ config: { ...fullConfig }
387
+ };
388
+ return handle;
389
+ }
390
+ },
391
+
392
+ graph3d: (config = {}) => {
393
+ const terminalId = getNextId('graph3d');
394
+ // Convert StoneArrays in config (e.g., axes.t.values) to plain JS arrays
395
+ const fullConfig = deepConvertStoneArrays({
396
+ title: config.title || 'Scene',
397
+ ...config
398
+ });
399
+
400
+ if (isAdapterMode) {
401
+ // New adapter mode - create via adapter
402
+ context.outputAdapter.createTerminal(terminalId, 'graph3d', fullConfig);
403
+ return new TerminalHandle('graph3d', fullConfig, terminalId, { outputAdapter: context.outputAdapter });
404
+ } else {
405
+ // Legacy mode - direct mutation
406
+ const handle = new TerminalHandle('graph3d', fullConfig, terminalId, { executor: context });
407
+ context.terminalsData[terminalId] = {
408
+ type: 'graph3d',
409
+ config: fullConfig,
410
+ objects: []
411
+ };
412
+ handle.ports = {
413
+ objects: [],
414
+ config: { ...fullConfig }
415
+ };
416
+ return handle;
417
+ }
418
+ }
419
+ };
420
+ }
421
+
422
+ /**
423
+ * Check if a value is a TerminalHandle
424
+ * @param {any} value - Value to check
425
+ * @returns {boolean}
426
+ */
427
+ export function isTerminalHandle(value) {
428
+ return value instanceof TerminalHandle || value?._type === 'TerminalHandle';
429
+ }
430
+
431
+ export default {
432
+ TerminalHandle,
433
+ createTerminalConstructors,
434
+ isTerminalHandle
435
+ };