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.
- package/README.md +52 -0
- package/StoneEngine.js +879 -0
- package/StoneEngineService.js +1727 -0
- package/adapters/FileSystemAdapter.js +230 -0
- package/adapters/OutputAdapter.js +208 -0
- package/adapters/index.js +6 -0
- package/cli/CLIOutputAdapter.js +196 -0
- package/cli/DaemonClient.js +349 -0
- package/cli/JSONOutputAdapter.js +135 -0
- package/cli/ReplSession.js +567 -0
- package/cli/ViewerServer.js +590 -0
- package/cli/commands/check.js +84 -0
- package/cli/commands/daemon.js +189 -0
- package/cli/commands/kill.js +66 -0
- package/cli/commands/package.js +713 -0
- package/cli/commands/ps.js +65 -0
- package/cli/commands/run.js +537 -0
- package/cli/entry.js +169 -0
- package/cli/index.js +14 -0
- package/cli/stonec.js +358 -0
- package/cli/test-compiler.js +181 -0
- package/cli/viewer/index.html +495 -0
- package/daemon/IPCServer.js +455 -0
- package/daemon/ProcessManager.js +327 -0
- package/daemon/ProcessRunner.js +307 -0
- package/daemon/daemon.js +398 -0
- package/daemon/index.js +16 -0
- package/frontend/analysis/index.js +5 -0
- package/frontend/analysis/livenessAnalyzer.js +568 -0
- package/frontend/analysis/treeShaker.js +265 -0
- package/frontend/index.js +20 -0
- package/frontend/parsing/astBuilder.js +2196 -0
- package/frontend/parsing/index.js +7 -0
- package/frontend/parsing/sonParser.js +592 -0
- package/frontend/parsing/stoneAstTypes.js +703 -0
- package/frontend/parsing/terminal-registry.js +435 -0
- package/frontend/parsing/tokenizer.js +692 -0
- package/frontend/type-checker/OverloadedFunctionType.js +43 -0
- package/frontend/type-checker/TypeEnvironment.js +165 -0
- package/frontend/type-checker/bidirectionalInference.js +149 -0
- package/frontend/type-checker/index.js +10 -0
- package/frontend/type-checker/moduleAnalysis.js +248 -0
- package/frontend/type-checker/operatorMappings.js +35 -0
- package/frontend/type-checker/overloadResolution.js +605 -0
- package/frontend/type-checker/typeChecker.js +452 -0
- package/frontend/type-checker/typeCompatibility.js +389 -0
- package/frontend/type-checker/visitors/controlFlow.js +483 -0
- package/frontend/type-checker/visitors/functions.js +604 -0
- package/frontend/type-checker/visitors/index.js +38 -0
- package/frontend/type-checker/visitors/literals.js +341 -0
- package/frontend/type-checker/visitors/modules.js +159 -0
- package/frontend/type-checker/visitors/operators.js +109 -0
- package/frontend/type-checker/visitors/statements.js +768 -0
- package/frontend/types/index.js +5 -0
- package/frontend/types/operatorMap.js +134 -0
- package/frontend/types/types.js +2046 -0
- package/frontend/utils/errorCollector.js +244 -0
- package/frontend/utils/index.js +5 -0
- package/frontend/utils/moduleResolver.js +479 -0
- package/package.json +50 -0
- package/packages/browserCache.js +359 -0
- package/packages/fetcher.js +236 -0
- package/packages/index.js +130 -0
- package/packages/lockfile.js +271 -0
- package/packages/manifest.js +291 -0
- package/packages/packageResolver.js +356 -0
- package/packages/resolver.js +310 -0
- package/packages/semver.js +635 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stone Module Tree Shaker
|
|
3
|
+
*
|
|
4
|
+
* Analyzes imports to determine which exports are actually used from each module,
|
|
5
|
+
* enabling optimization of module loading and reducing memory usage.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Analyzes import statements to track which exports are used
|
|
9
|
+
* - Filters module exports to only include used names
|
|
10
|
+
* - Detects unused imports for warnings
|
|
11
|
+
* - Supports selective imports, namespace imports, and re-exports
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* const analyzer = new ImportAnalyzer();
|
|
15
|
+
* const usedExports = analyzer.analyze(ast);
|
|
16
|
+
* // usedExports is Map<modulePath, Set<exportName>>
|
|
17
|
+
*
|
|
18
|
+
* const shaker = new TreeShaker();
|
|
19
|
+
* const filteredExports = shaker.filterExports(moduleExports, usedExports.get(modulePath));
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Analyzes an AST to determine which exports are used from each imported module
|
|
24
|
+
*/
|
|
25
|
+
export class ImportAnalyzer {
|
|
26
|
+
constructor() {
|
|
27
|
+
// Map from module path to Set of imported names
|
|
28
|
+
this.usedExports = new Map();
|
|
29
|
+
// Map from local name to { modulePath, importedName }
|
|
30
|
+
this.importedBindings = new Map();
|
|
31
|
+
// Set of local names that are actually referenced in code
|
|
32
|
+
this.referencedNames = new Set();
|
|
33
|
+
// Track namespace imports: localName -> modulePath
|
|
34
|
+
this.namespaceImports = new Map();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Analyze an AST and return a map of used exports per module
|
|
39
|
+
* @param {Object} ast - The parsed AST
|
|
40
|
+
* @returns {Map<string, Set<string>>} Map from module path to set of used export names
|
|
41
|
+
*/
|
|
42
|
+
analyze(ast) {
|
|
43
|
+
this.usedExports.clear();
|
|
44
|
+
this.importedBindings.clear();
|
|
45
|
+
this.referencedNames.clear();
|
|
46
|
+
this.namespaceImports.clear();
|
|
47
|
+
|
|
48
|
+
// First pass: collect all imports
|
|
49
|
+
this._collectImports(ast);
|
|
50
|
+
|
|
51
|
+
// Second pass: collect all identifier references
|
|
52
|
+
this._collectReferences(ast);
|
|
53
|
+
|
|
54
|
+
// Third pass: determine which imports are actually used
|
|
55
|
+
return this._computeUsedExports();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Collect all import statements from the AST
|
|
60
|
+
*/
|
|
61
|
+
_collectImports(ast) {
|
|
62
|
+
if (!ast || !ast.imports) return;
|
|
63
|
+
|
|
64
|
+
for (const importNode of ast.imports) {
|
|
65
|
+
if (importNode.type === 'ImportStatement') {
|
|
66
|
+
const modulePath = importNode.modulePath;
|
|
67
|
+
|
|
68
|
+
if (!this.usedExports.has(modulePath)) {
|
|
69
|
+
this.usedExports.set(modulePath, new Set());
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
for (const spec of importNode.specifiers) {
|
|
73
|
+
const importedName = spec.importedName || spec.localName;
|
|
74
|
+
const localName = spec.localName;
|
|
75
|
+
|
|
76
|
+
// Track the binding
|
|
77
|
+
this.importedBindings.set(localName, {
|
|
78
|
+
modulePath,
|
|
79
|
+
importedName,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
} else if (importNode.type === 'NamespaceImportStatement') {
|
|
83
|
+
const modulePath = importNode.modulePath;
|
|
84
|
+
const localName = importNode.alias || this._getModuleLastSegment(modulePath);
|
|
85
|
+
|
|
86
|
+
// Namespace imports use all exports (marked with '*')
|
|
87
|
+
if (!this.usedExports.has(modulePath)) {
|
|
88
|
+
this.usedExports.set(modulePath, new Set());
|
|
89
|
+
}
|
|
90
|
+
this.usedExports.get(modulePath).add('*');
|
|
91
|
+
this.namespaceImports.set(localName, modulePath);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Collect all identifier references in the AST
|
|
98
|
+
*/
|
|
99
|
+
_collectReferences(ast) {
|
|
100
|
+
this._walkAST(ast, (node) => {
|
|
101
|
+
// Identifier nodes (variable references like `x` in `y = x + 1`)
|
|
102
|
+
if (node.type === 'Identifier') {
|
|
103
|
+
this.referencedNames.add(node.name);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// FunctionCall nodes have funcName as a string (not an Identifier)
|
|
107
|
+
if (node.type === 'FunctionCall' && node.funcName) {
|
|
108
|
+
this.referencedNames.add(node.funcName);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Handle member access on namespace imports: ns.foo
|
|
112
|
+
if (node.type === 'MemberAccess' && node.object?.type === 'Identifier') {
|
|
113
|
+
const objName = node.object.name;
|
|
114
|
+
if (this.namespaceImports.has(objName) && node.property?.name) {
|
|
115
|
+
// Track the specific property accessed
|
|
116
|
+
const modulePath = this.namespaceImports.get(objName);
|
|
117
|
+
if (this.usedExports.has(modulePath)) {
|
|
118
|
+
this.usedExports.get(modulePath).add(node.property.name);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Compute which exports are actually used based on references
|
|
127
|
+
*/
|
|
128
|
+
_computeUsedExports() {
|
|
129
|
+
// For each imported binding that's referenced, mark its export as used
|
|
130
|
+
for (const [localName, bindingInfo] of this.importedBindings) {
|
|
131
|
+
if (this.referencedNames.has(localName)) {
|
|
132
|
+
const { modulePath, importedName } = bindingInfo;
|
|
133
|
+
if (this.usedExports.has(modulePath)) {
|
|
134
|
+
this.usedExports.get(modulePath).add(importedName);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return this.usedExports;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Get unused imports (imports that are never referenced)
|
|
144
|
+
* @returns {Array<{localName, modulePath, importedName}>}
|
|
145
|
+
*/
|
|
146
|
+
getUnusedImports() {
|
|
147
|
+
const unused = [];
|
|
148
|
+
for (const [localName, bindingInfo] of this.importedBindings) {
|
|
149
|
+
if (!this.referencedNames.has(localName)) {
|
|
150
|
+
unused.push({
|
|
151
|
+
localName,
|
|
152
|
+
modulePath: bindingInfo.modulePath,
|
|
153
|
+
importedName: bindingInfo.importedName,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return unused;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Walk the AST and call callback for each node
|
|
162
|
+
*/
|
|
163
|
+
_walkAST(node, callback) {
|
|
164
|
+
if (!node || typeof node !== 'object') return;
|
|
165
|
+
|
|
166
|
+
callback(node);
|
|
167
|
+
|
|
168
|
+
// Skip certain node types that don't contain code references
|
|
169
|
+
if (node.type === 'ImportStatement' || node.type === 'NamespaceImportStatement') {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Recursively walk all properties
|
|
174
|
+
for (const key of Object.keys(node)) {
|
|
175
|
+
const value = node[key];
|
|
176
|
+
if (Array.isArray(value)) {
|
|
177
|
+
for (const item of value) {
|
|
178
|
+
this._walkAST(item, callback);
|
|
179
|
+
}
|
|
180
|
+
} else if (value && typeof value === 'object' && value.type) {
|
|
181
|
+
this._walkAST(value, callback);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Get the last segment of a module path
|
|
188
|
+
*/
|
|
189
|
+
_getModuleLastSegment(modulePath) {
|
|
190
|
+
const segments = modulePath.split('/');
|
|
191
|
+
return segments[segments.length - 1];
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Filters module exports based on what's actually used
|
|
197
|
+
*/
|
|
198
|
+
export class TreeShaker {
|
|
199
|
+
/**
|
|
200
|
+
* Filter a module's exports to only include used names
|
|
201
|
+
* @param {Object} moduleExports - The full exports object from a module
|
|
202
|
+
* @param {Set<string>} usedNames - Set of export names that are actually used
|
|
203
|
+
* @returns {Object} Filtered exports object
|
|
204
|
+
*/
|
|
205
|
+
filterExports(moduleExports, usedNames) {
|
|
206
|
+
if (!moduleExports || !usedNames) {
|
|
207
|
+
return moduleExports;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// If '*' is in usedNames, return all exports (namespace import)
|
|
211
|
+
if (usedNames.has('*')) {
|
|
212
|
+
return moduleExports;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Filter to only include used exports
|
|
216
|
+
const filtered = {};
|
|
217
|
+
for (const name of usedNames) {
|
|
218
|
+
if (name in moduleExports) {
|
|
219
|
+
filtered[name] = moduleExports[name];
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return filtered;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Analyze an AST and return tree-shaking metadata
|
|
228
|
+
* @param {Object} ast - The parsed AST
|
|
229
|
+
* @returns {Object} Tree-shaking metadata
|
|
230
|
+
*/
|
|
231
|
+
analyzeAndShake(ast) {
|
|
232
|
+
const analyzer = new ImportAnalyzer();
|
|
233
|
+
const usedExports = analyzer.analyze(ast);
|
|
234
|
+
const unusedImports = analyzer.getUnusedImports();
|
|
235
|
+
|
|
236
|
+
return {
|
|
237
|
+
usedExports,
|
|
238
|
+
unusedImports,
|
|
239
|
+
hasUnusedImports: unusedImports.length > 0,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Create a tree shaker with import analysis
|
|
246
|
+
* @param {Object} ast - The parsed AST
|
|
247
|
+
* @returns {Object} Object with { usedExports, filterExports, unusedImports }
|
|
248
|
+
*/
|
|
249
|
+
export function createTreeShaker(ast) {
|
|
250
|
+
const analyzer = new ImportAnalyzer();
|
|
251
|
+
const usedExports = analyzer.analyze(ast);
|
|
252
|
+
const unusedImports = analyzer.getUnusedImports();
|
|
253
|
+
const shaker = new TreeShaker();
|
|
254
|
+
|
|
255
|
+
return {
|
|
256
|
+
usedExports,
|
|
257
|
+
unusedImports,
|
|
258
|
+
filterExports: (moduleExports, modulePath) => {
|
|
259
|
+
const used = usedExports.get(modulePath);
|
|
260
|
+
return shaker.filterExports(moduleExports, used);
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export default TreeShaker;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stone Frontend - Barrel exports
|
|
3
|
+
*
|
|
4
|
+
* Re-exports all frontend modules: parsing, types, type-checker, analysis, utils
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Parsing
|
|
8
|
+
export * from './parsing/index.js';
|
|
9
|
+
|
|
10
|
+
// Types
|
|
11
|
+
export * from './types/index.js';
|
|
12
|
+
|
|
13
|
+
// Type Checker
|
|
14
|
+
export * from './type-checker/index.js';
|
|
15
|
+
|
|
16
|
+
// Analysis
|
|
17
|
+
export * from './analysis/index.js';
|
|
18
|
+
|
|
19
|
+
// Utils
|
|
20
|
+
export * from './utils/index.js';
|