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,479 @@
1
+ /**
2
+ * Stone Module Resolver
3
+ *
4
+ * Resolution order:
5
+ * 1. Built-in modules (primitives, plots)
6
+ * 2. Standard library (.stn builtins: math, array, stats, etc.)
7
+ * 3. Local stone_modules/ (at project root, where package.son lives)
8
+ * 4. Global ~/.stone/stone_modules/
9
+ * 5. File-based resolution (relative paths, filesSource)
10
+ */
11
+
12
+ import {
13
+ resolvePath,
14
+ resolveRelative,
15
+ getDirectory,
16
+ } from '../../../utils/filePathResolver.js';
17
+ import { extractCodeSection } from '../../fileFormat/stoneFileParser.js';
18
+
19
+ // Import standard library modules
20
+ import primitives from '../../standard-library/primitives.js';
21
+
22
+ // Embedded .stn standard library content (generated from .stn files)
23
+ // To regenerate: node scripts/build-stn-content.js
24
+ import { STN_BUILTIN_CONTENT } from '../../standard-library/stn-content.generated.js';
25
+
26
+ /**
27
+ * Module cache for tracking loaded modules
28
+ */
29
+ class ModuleCache {
30
+ constructor() {
31
+ this.modules = new Map();
32
+ this.loading = new Set();
33
+ }
34
+
35
+ has(modulePath) {
36
+ return this.modules.has(modulePath);
37
+ }
38
+
39
+ get(modulePath) {
40
+ return this.modules.get(modulePath);
41
+ }
42
+
43
+ set(modulePath, moduleData) {
44
+ this.modules.set(modulePath, moduleData);
45
+ }
46
+
47
+ isLoading(modulePath) {
48
+ return this.loading.has(modulePath);
49
+ }
50
+
51
+ startLoading(modulePath) {
52
+ this.loading.add(modulePath);
53
+ }
54
+
55
+ finishLoading(modulePath) {
56
+ this.loading.delete(modulePath);
57
+ }
58
+
59
+ clear() {
60
+ this.modules.clear();
61
+ this.loading.clear();
62
+ }
63
+
64
+ entries() {
65
+ return this.modules.entries();
66
+ }
67
+
68
+ // Custom serialization - only export minimal dependency data
69
+ toJSON() {
70
+ const modules = {};
71
+ for (const [key, value] of this.modules) {
72
+ modules[key] = {
73
+ fileId: value.fileId,
74
+ modulePath: value.modulePath,
75
+ isBuiltin: value.isBuiltin
76
+ };
77
+ }
78
+ return { modules, loading: [] };
79
+ }
80
+ }
81
+
82
+ export class ModuleResolver {
83
+ constructor(options = {}) {
84
+ this.cache = new ModuleCache();
85
+ this.filesSource = options.filesSource || null;
86
+ this.currentFilePath = null;
87
+ this.fileLoader = options.fileLoader || null;
88
+ this.builtinModules = this.createBuiltinModules();
89
+
90
+ // Package system support (optional)
91
+ // PackageContext handles stone_modules resolution
92
+ this.packageContext = options.packageContext || null;
93
+ }
94
+
95
+ /**
96
+ * Set the package context for stone_modules resolution
97
+ */
98
+ setPackageContext(context) {
99
+ this.packageContext = context;
100
+ }
101
+
102
+ /**
103
+ * Create built-in module exports
104
+ * Imports from standard-library/ modules
105
+ * Note: Most standard library modules are now .stn (in STN_BUILTIN_CONTENT)
106
+ */
107
+ createBuiltinModules() {
108
+ return {
109
+ // Primitives module (JS) - all primitives with overload wrappers
110
+ 'primitives': primitives,
111
+ // Note: stats, math, builtins are now .stn modules (see STN_BUILTIN_CONTENT)
112
+ // Other modules (array, string, linalg, complex, random) being migrated to .stn
113
+
114
+ // Plots module - runtime terminal constructors (actual exports bound by executor)
115
+ // This is a placeholder so the module resolver recognizes 'plots' as valid
116
+ 'plots': {
117
+ graph2d: null, // Bound at runtime by executor
118
+ graph3d: null, // Bound at runtime by executor
119
+ },
120
+
121
+ // Note: 'file' module is now a .stn builtin (see STN_BUILTIN_CONTENT)
122
+ };
123
+ }
124
+
125
+ /**
126
+ * Check if a module is a runtime module (needs executor binding)
127
+ */
128
+ isRuntimeModule(modulePath) {
129
+ return modulePath === 'plots';
130
+ }
131
+
132
+ /**
133
+ * Check if a module is a .stn builtin
134
+ */
135
+ isStnBuiltinModule(modulePath) {
136
+ return modulePath in STN_BUILTIN_CONTENT;
137
+ }
138
+
139
+ /**
140
+ * Get .stn builtin content
141
+ */
142
+ getStnBuiltinContent(modulePath) {
143
+ return STN_BUILTIN_CONTENT[modulePath];
144
+ }
145
+
146
+ setFilesSource(filesSource) {
147
+ this.filesSource = filesSource;
148
+ }
149
+
150
+ setCurrentFilePath(path) {
151
+ this.currentFilePath = path;
152
+ }
153
+
154
+ setFileLoader(loader) {
155
+ this.fileLoader = loader;
156
+ }
157
+
158
+ getCurrentFilePath() {
159
+ return this.currentFilePath;
160
+ }
161
+
162
+ resolveModulePath(modulePath) {
163
+ const currentFilePath = this.currentFilePath;
164
+
165
+ if ((modulePath.startsWith('./') || modulePath.startsWith('../')) && currentFilePath) {
166
+ const currentDir = getDirectory(currentFilePath);
167
+ return resolveRelative(currentDir, modulePath);
168
+ }
169
+
170
+ return modulePath.replace(/^\.\//, '');
171
+ }
172
+
173
+ isBuiltinModule(modulePath) {
174
+ return this.builtinModules.hasOwnProperty(modulePath);
175
+ }
176
+
177
+ getBuiltinModule(modulePath) {
178
+ return this.builtinModules[modulePath];
179
+ }
180
+
181
+ /**
182
+ * Check if a file ID corresponds to an actual .stn file (not a folder)
183
+ */
184
+ isStoneFile(fileId) {
185
+ if (!fileId || !this.filesSource) return false;
186
+ const files = this.filesSource instanceof Map
187
+ ? Array.from(this.filesSource.values())
188
+ : Array.isArray(this.filesSource) ? this.filesSource : [];
189
+ const file = files.find(f => (f._id || f.id) === fileId);
190
+ return file && file.name && file.name.endsWith('.stn');
191
+ }
192
+
193
+ /**
194
+ * Resolve module path to file ID
195
+ * @param {string} modulePath - The module path to resolve
196
+ * @param {string|null} inferredFilename - Optional filename to append for directory imports
197
+ * (e.g., for "import stats from 'dir'" -> tries "dir/stats.stn")
198
+ * @returns {string|null} The resolved file ID or null if not found
199
+ */
200
+ resolveToFileId(modulePath, inferredFilename = null) {
201
+ // If no filesSource but we have a fileLoader, use resolveModulePath
202
+ // This supports file-based loading with relative paths
203
+ if (!this.filesSource && this.fileLoader) {
204
+ return this.resolveModulePath(modulePath);
205
+ }
206
+
207
+ if (!this.filesSource) {
208
+ return null;
209
+ }
210
+
211
+ const currentFilePath = this.currentFilePath;
212
+
213
+ // 1. Try exact path first (must be an actual .stn file, not a folder)
214
+ let fileId = resolvePath(modulePath, this.filesSource, currentFilePath);
215
+ if (fileId && this.isStoneFile(fileId)) {
216
+ return fileId;
217
+ }
218
+
219
+ // 2. Try with inferred filename (directory + inferred filename resolution)
220
+ // This enables: import stats from "core logic/math" -> "core logic/math/stats.stn"
221
+ if (inferredFilename) {
222
+ const inferredPath = `${modulePath}/${inferredFilename}`;
223
+ fileId = resolvePath(inferredPath, this.filesSource, currentFilePath);
224
+ if (fileId && this.isStoneFile(fileId)) {
225
+ return fileId;
226
+ }
227
+ }
228
+
229
+ // 3. Try index.stn fallback
230
+ fileId = resolvePath(modulePath + '/index.stn', this.filesSource, currentFilePath);
231
+ if (fileId && this.isStoneFile(fileId)) {
232
+ return fileId;
233
+ }
234
+
235
+ return null;
236
+ }
237
+
238
+ /**
239
+ * Load a module by path
240
+ * @param {string} modulePath - The module path to load
241
+ * @param {function} parseFunction - Function to parse source code
242
+ * @param {string|null} inferredFilename - Optional filename for directory inference
243
+ */
244
+ async loadModule(modulePath, parseFunction, inferredFilename = null) {
245
+ // Check JS builtins first (fast path)
246
+ if (this.isBuiltinModule(modulePath)) {
247
+ return {
248
+ isBuiltin: true,
249
+ exports: this.getBuiltinModule(modulePath),
250
+ modulePath,
251
+ };
252
+ }
253
+
254
+ if (this.cache.has(modulePath)) {
255
+ return this.cache.get(modulePath);
256
+ }
257
+
258
+ // Check .stn builtins - these are parsed and executed like regular modules
259
+ if (this.isStnBuiltinModule(modulePath)) {
260
+
261
+ if (this.cache.isLoading(modulePath)) {
262
+ const error = new Error(`Circular dependency detected: ${modulePath}`);
263
+ error.stage = 'module_load';
264
+ error.type = 'module';
265
+ error.module = modulePath;
266
+ throw error;
267
+ }
268
+
269
+ this.cache.startLoading(modulePath);
270
+
271
+ try {
272
+ const stnContent = this.getStnBuiltinContent(modulePath);
273
+ const ast = parseFunction(stnContent, { filename: `<builtin:${modulePath}>` });
274
+
275
+ const moduleData = {
276
+ isBuiltin: false, // Treated as regular module for execution
277
+ isStnBuiltin: true, // Mark as .stn builtin for reference
278
+ ast,
279
+ fileId: null,
280
+ modulePath,
281
+ exports: null,
282
+ };
283
+
284
+ this.cache.set(modulePath, moduleData);
285
+ this.cache.finishLoading(modulePath);
286
+
287
+ return moduleData;
288
+ } catch (error) {
289
+ this.cache.finishLoading(modulePath);
290
+ const parseErr = new Error(`Failed to parse .stn builtin '${modulePath}': ${error.message}`);
291
+ parseErr.stage = 'module_load';
292
+ parseErr.type = 'module';
293
+ parseErr.module = modulePath;
294
+ throw parseErr;
295
+ }
296
+ }
297
+
298
+ if (this.cache.isLoading(modulePath)) {
299
+ const error = new Error(`Circular dependency detected: ${modulePath}`);
300
+ error.stage = 'module_load';
301
+ error.type = 'module';
302
+ error.module = modulePath;
303
+ throw error;
304
+ }
305
+
306
+ // Try stone_modules resolution first (if package context is available)
307
+ // This handles: import foo from bar -> stone_modules/bar/main.stn
308
+ if (this.packageContext && !modulePath.startsWith('./') && !modulePath.startsWith('../')) {
309
+ const packagePath = await this.packageContext.resolveModule(
310
+ modulePath,
311
+ this.currentFilePath,
312
+ { isBuiltin: (m) => this.isBuiltinModule(m) || this.isStnBuiltinModule(m) }
313
+ );
314
+
315
+ if (packagePath) {
316
+ // Load from resolved package path
317
+ return this.loadModuleFromPath(packagePath, modulePath, parseFunction);
318
+ }
319
+ }
320
+
321
+ // Pass inferredFilename for directory + inferred filename resolution
322
+ const fileId = this.resolveToFileId(modulePath, inferredFilename);
323
+ if (!fileId) {
324
+ // Provide helpful error message for inferred paths
325
+ let errorMsg = `Module not found: ${modulePath}`;
326
+ if (inferredFilename) {
327
+ errorMsg += ` (also tried ${modulePath}/${inferredFilename}.stn)`;
328
+ }
329
+ if (this.packageContext) {
330
+ errorMsg += ` (also checked stone_modules)`;
331
+ }
332
+ const error = new Error(errorMsg);
333
+ error.stage = 'module_load';
334
+ error.type = 'module';
335
+ error.module = modulePath;
336
+ throw error;
337
+ }
338
+
339
+ this.cache.startLoading(modulePath);
340
+
341
+ try {
342
+ if (!this.fileLoader) {
343
+ const error = new Error('No file loader configured for module resolver');
344
+ error.stage = 'module_load';
345
+ error.type = 'module';
346
+ throw error;
347
+ }
348
+
349
+ const fileContent = await this.fileLoader(fileId);
350
+ if (!fileContent) {
351
+ const error = new Error(`Failed to load module content: ${modulePath}`);
352
+ error.stage = 'module_load';
353
+ error.type = 'module';
354
+ error.module = modulePath;
355
+ throw error;
356
+ }
357
+
358
+ const rawContent = fileContent.content || fileContent.code || fileContent.data || fileContent;
359
+ const codeOnly = typeof rawContent === 'string' ? extractCodeSection(rawContent) : rawContent;
360
+ const ast = parseFunction(codeOnly, { filename: modulePath });
361
+
362
+ const moduleData = {
363
+ isBuiltin: false,
364
+ ast,
365
+ fileId,
366
+ modulePath,
367
+ exports: null,
368
+ };
369
+
370
+ this.cache.set(modulePath, moduleData);
371
+ this.cache.finishLoading(modulePath);
372
+
373
+ return moduleData;
374
+ } catch (error) {
375
+ this.cache.finishLoading(modulePath);
376
+ throw error;
377
+ }
378
+ }
379
+
380
+ /**
381
+ * Load a module from a resolved file path (used by package resolution)
382
+ */
383
+ async loadModuleFromPath(filePath, modulePath, parseFunction) {
384
+ this.cache.startLoading(modulePath);
385
+
386
+ try {
387
+ // Read file content using package context
388
+ let fileContent = null;
389
+
390
+ if (this.packageContext && this.packageContext.readFile) {
391
+ fileContent = await this.packageContext.readFile(filePath);
392
+ } else if (this.fileLoader) {
393
+ fileContent = await this.fileLoader(filePath);
394
+ }
395
+
396
+ if (!fileContent) {
397
+ const error = new Error(`Failed to load module content: ${modulePath} (${filePath})`);
398
+ error.stage = 'module_load';
399
+ error.type = 'module';
400
+ error.module = modulePath;
401
+ throw error;
402
+ }
403
+
404
+ const rawContent = typeof fileContent === 'string' ? fileContent :
405
+ (fileContent.content || fileContent.code || fileContent.data || fileContent);
406
+ const codeOnly = typeof rawContent === 'string' ? extractCodeSection(rawContent) : rawContent;
407
+ const ast = parseFunction(codeOnly, { filename: filePath });
408
+
409
+ const moduleData = {
410
+ isBuiltin: false,
411
+ isPackageModule: true,
412
+ ast,
413
+ fileId: filePath,
414
+ modulePath,
415
+ exports: null,
416
+ };
417
+
418
+ this.cache.set(modulePath, moduleData);
419
+ this.cache.finishLoading(modulePath);
420
+
421
+ return moduleData;
422
+ } catch (error) {
423
+ this.cache.finishLoading(modulePath);
424
+ throw error;
425
+ }
426
+ }
427
+
428
+ getModuleName(modulePath) {
429
+ const segments = modulePath.split('/');
430
+ return segments[segments.length - 1];
431
+ }
432
+
433
+ getExportedNames(ast) {
434
+ if (!ast || !ast.exports) return [];
435
+
436
+ return ast.exports.map(exportStmt => {
437
+ const decl = exportStmt.declaration;
438
+ if (decl.type === 'FunctionDefinition') return decl.name;
439
+ if (decl.type === 'Assignment') return decl.target;
440
+ return null;
441
+ }).filter(Boolean);
442
+ }
443
+
444
+ clearCache() {
445
+ this.cache.clear();
446
+ }
447
+
448
+ // Custom serialization - exclude filesSource to avoid serializing entire file system
449
+ toJSON() {
450
+ return {
451
+ cache: this.cache,
452
+ // filesSource excluded - runtime context only, not needed for serialization
453
+ };
454
+ }
455
+ }
456
+
457
+ export function createModuleResolver(options = {}) {
458
+ return new ModuleResolver(options);
459
+ }
460
+
461
+ /**
462
+ * Create a module resolver with package support for Node.js
463
+ * @param {object} options - Resolver options
464
+ * @returns {Promise<ModuleResolver>} Configured module resolver
465
+ */
466
+ export async function createPackageAwareResolver(options = {}) {
467
+ const resolver = new ModuleResolver(options);
468
+
469
+ // Try to set up package context
470
+ try {
471
+ const { createNodePackageContext } = await import('../../packages/packageResolver.js');
472
+ const packageContext = await createNodePackageContext();
473
+ resolver.setPackageContext(packageContext);
474
+ } catch (e) {
475
+ // Package support not available, continue without it
476
+ }
477
+
478
+ return resolver;
479
+ }
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "stone-lang",
3
+ "version": "0.1.0",
4
+ "description": "Stone - A modern programming language for data science and numerical computing",
5
+ "keywords": [
6
+ "stone",
7
+ "programming-language",
8
+ "data-science",
9
+ "numerical-computing",
10
+ "interpreter",
11
+ "cli"
12
+ ],
13
+ "author": "Alvei",
14
+ "license": "MIT",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/alvei/stone-lang"
18
+ },
19
+ "homepage": "https://stone-lang.dev",
20
+ "bugs": {
21
+ "url": "https://github.com/alvei/stone-lang/issues"
22
+ },
23
+ "type": "module",
24
+ "bin": {
25
+ "stone": "./cli/entry.js"
26
+ },
27
+ "main": "./StoneEngine.js",
28
+ "exports": {
29
+ ".": "./StoneEngine.js",
30
+ "./engine": "./StoneEngine.js"
31
+ },
32
+ "engines": {
33
+ "node": ">=18.0.0"
34
+ },
35
+ "dependencies": {
36
+ "commander": "^12.1.0"
37
+ },
38
+ "files": [
39
+ "cli/",
40
+ "frontend/",
41
+ "backend/",
42
+ "adapters/",
43
+ "stdlib/",
44
+ "packages/",
45
+ "daemon/",
46
+ "StoneEngine.js",
47
+ "StoneEngineService.js",
48
+ "README.md"
49
+ ]
50
+ }