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,271 @@
1
+ /**
2
+ * Stone Package Lock File Handler
3
+ *
4
+ * Handles reading and writing package.lock.son files.
5
+ * Ensures reproducible builds with locked versions.
6
+ */
7
+
8
+ import { parseSON, stringifySON } from '../frontend/parsing/sonParser.js';
9
+ import { parseVersion, valid as validVersion } from './semver.js';
10
+
11
+ /**
12
+ * Lock file version - increment when format changes
13
+ */
14
+ const LOCK_VERSION = 1;
15
+
16
+ /**
17
+ * Lock file error
18
+ */
19
+ export class LockFileError extends Error {
20
+ constructor(message) {
21
+ super(message);
22
+ this.name = 'LockFileError';
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Locked package entry
28
+ */
29
+ export class LockedPackage {
30
+ constructor(data = {}) {
31
+ this.name = data.name || '';
32
+ this.version = data.version || '';
33
+ this.source = data.source || null;
34
+ this.integrity = data.integrity || null;
35
+ this.dependencies = data.dependencies || {};
36
+ }
37
+
38
+ toObject() {
39
+ const obj = {
40
+ version: this.version,
41
+ };
42
+
43
+ if (this.source) {
44
+ obj.source = this.source;
45
+ }
46
+ if (this.integrity) {
47
+ obj.integrity = this.integrity;
48
+ }
49
+ if (Object.keys(this.dependencies).length > 0) {
50
+ obj.dependencies = this.dependencies;
51
+ }
52
+
53
+ return obj;
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Lock file representation
59
+ */
60
+ export class LockFile {
61
+ constructor() {
62
+ this.lockVersion = LOCK_VERSION;
63
+ this.packages = new Map(); // name -> LockedPackage
64
+ }
65
+
66
+ /**
67
+ * Add or update a locked package
68
+ */
69
+ setPackage(name, version, source = null, integrity = null, dependencies = {}) {
70
+ this.packages.set(name, new LockedPackage({
71
+ name,
72
+ version,
73
+ source,
74
+ integrity,
75
+ dependencies,
76
+ }));
77
+ }
78
+
79
+ /**
80
+ * Get a locked package
81
+ */
82
+ getPackage(name) {
83
+ return this.packages.get(name) || null;
84
+ }
85
+
86
+ /**
87
+ * Check if a package is locked
88
+ */
89
+ hasPackage(name) {
90
+ return this.packages.has(name);
91
+ }
92
+
93
+ /**
94
+ * Get the locked version of a package
95
+ */
96
+ getVersion(name) {
97
+ const pkg = this.packages.get(name);
98
+ return pkg ? pkg.version : null;
99
+ }
100
+
101
+ /**
102
+ * Remove a locked package
103
+ */
104
+ removePackage(name) {
105
+ this.packages.delete(name);
106
+ }
107
+
108
+ /**
109
+ * Clear all locked packages
110
+ */
111
+ clear() {
112
+ this.packages.clear();
113
+ }
114
+
115
+ /**
116
+ * Get all package names
117
+ */
118
+ getPackageNames() {
119
+ return Array.from(this.packages.keys());
120
+ }
121
+
122
+ /**
123
+ * Validate the lock file
124
+ */
125
+ validate() {
126
+ for (const [name, pkg] of this.packages) {
127
+ if (!pkg.version) {
128
+ throw new LockFileError(`Missing version for package: ${name}`);
129
+ }
130
+ if (!validVersion(pkg.version)) {
131
+ throw new LockFileError(`Invalid version for ${name}: ${pkg.version}`);
132
+ }
133
+ }
134
+ return true;
135
+ }
136
+
137
+ /**
138
+ * Convert to plain object for serialization
139
+ */
140
+ toObject() {
141
+ const packages = {};
142
+
143
+ for (const [name, pkg] of this.packages) {
144
+ packages[name] = pkg.toObject();
145
+ }
146
+
147
+ return {
148
+ lockVersion: this.lockVersion,
149
+ packages,
150
+ };
151
+ }
152
+
153
+ /**
154
+ * Convert to .son string
155
+ */
156
+ toString() {
157
+ return stringifySON(this.toObject());
158
+ }
159
+
160
+ /**
161
+ * Create from resolved dependencies
162
+ * @param {Map|object} resolved - Map of name to { version, source?, integrity? }
163
+ */
164
+ static fromResolved(resolved) {
165
+ const lockFile = new LockFile();
166
+
167
+ const entries = resolved instanceof Map
168
+ ? Array.from(resolved.entries())
169
+ : Object.entries(resolved);
170
+
171
+ for (const [name, info] of entries) {
172
+ lockFile.setPackage(
173
+ name,
174
+ info.version,
175
+ info.source || null,
176
+ info.integrity || null,
177
+ info.dependencies || {}
178
+ );
179
+ }
180
+
181
+ return lockFile;
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Parse a package.lock.son file content
187
+ * @param {string} content - The file content
188
+ * @param {string} filename - Optional filename for error messages
189
+ * @returns {LockFile} Parsed lock file
190
+ */
191
+ export function parseLockFile(content, filename = 'package.lock.son') {
192
+ let data;
193
+
194
+ try {
195
+ data = parseSON(content, filename);
196
+ } catch (e) {
197
+ throw new LockFileError(`Failed to parse lock file: ${e.message}`);
198
+ }
199
+
200
+ // Check version compatibility
201
+ if (data.lockVersion && data.lockVersion > LOCK_VERSION) {
202
+ throw new LockFileError(
203
+ `Lock file version ${data.lockVersion} is newer than supported version ${LOCK_VERSION}. ` +
204
+ 'Please update your Stone installation.'
205
+ );
206
+ }
207
+
208
+ const lockFile = new LockFile();
209
+ lockFile.lockVersion = data.lockVersion || 1;
210
+
211
+ if (data.packages && typeof data.packages === 'object') {
212
+ for (const [name, pkgData] of Object.entries(data.packages)) {
213
+ lockFile.setPackage(
214
+ name,
215
+ pkgData.version,
216
+ pkgData.source,
217
+ pkgData.integrity,
218
+ pkgData.dependencies
219
+ );
220
+ }
221
+ }
222
+
223
+ lockFile.validate();
224
+ return lockFile;
225
+ }
226
+
227
+ /**
228
+ * Stringify a lock file to .son format
229
+ */
230
+ export function stringifyLockFile(lockFile) {
231
+ if (lockFile instanceof LockFile) {
232
+ return lockFile.toString();
233
+ }
234
+ return stringifySON(lockFile);
235
+ }
236
+
237
+ /**
238
+ * Check if a lock file is up to date with a manifest
239
+ * @param {LockFile} lockFile - The lock file
240
+ * @param {object} manifest - The package manifest
241
+ * @returns {{upToDate: boolean, missing: string[], extra: string[], outdated: string[]}}
242
+ */
243
+ export function checkLockFileStatus(lockFile, manifest) {
244
+ const deps = manifest.dependencies || {};
245
+ const locked = lockFile.getPackageNames();
246
+ const depNames = Object.keys(deps);
247
+
248
+ const missing = depNames.filter(name => !lockFile.hasPackage(name));
249
+ const extra = locked.filter(name => !deps[name]);
250
+
251
+ // Check if any locked versions are outside their range
252
+ // (This would require re-resolving, so we just flag any missing)
253
+ const outdated = []; // Would need to compare with constraints
254
+
255
+ return {
256
+ upToDate: missing.length === 0 && extra.length === 0,
257
+ missing,
258
+ extra,
259
+ outdated,
260
+ };
261
+ }
262
+
263
+ export default {
264
+ LockFile,
265
+ LockedPackage,
266
+ LockFileError,
267
+ parseLockFile,
268
+ stringifyLockFile,
269
+ checkLockFileStatus,
270
+ LOCK_VERSION,
271
+ };
@@ -0,0 +1,291 @@
1
+ /**
2
+ * Stone Package Manifest Handler
3
+ *
4
+ * Reads, writes, and validates package.son files.
5
+ */
6
+
7
+ import { parseSON, stringifySON, SONParseError } from '../frontend/parsing/sonParser.js';
8
+ import { parseVersion, parseRange, valid as validVersion } from './semver.js';
9
+
10
+ /**
11
+ * Manifest validation error
12
+ */
13
+ export class ManifestError extends Error {
14
+ constructor(message, field = null) {
15
+ super(message);
16
+ this.name = 'ManifestError';
17
+ this.field = field;
18
+ }
19
+ }
20
+
21
+ /**
22
+ * Parsed package manifest
23
+ */
24
+ export class PackageManifest {
25
+ constructor(data = {}) {
26
+ // Required fields
27
+ this.name = data.name || '';
28
+ this.version = data.version || '';
29
+
30
+ // Optional fields
31
+ this.entry = data.entry || 'main.stn';
32
+ this.description = data.description || '';
33
+ this.author = data.author || '';
34
+ this.license = data.license || '';
35
+ this.keywords = data.keywords || [];
36
+ this.repository = data.repository || '';
37
+
38
+ // Dependencies: { name: { version, source } }
39
+ this.dependencies = data.dependencies || {};
40
+
41
+ // Dev dependencies (not needed for runtime)
42
+ this.devDependencies = data.devDependencies || {};
43
+
44
+ // Raw data for any additional fields
45
+ this._raw = data;
46
+ }
47
+
48
+ /**
49
+ * Validate the manifest
50
+ * @throws {ManifestError} If validation fails
51
+ */
52
+ validate() {
53
+ // Required: name
54
+ if (!this.name) {
55
+ throw new ManifestError('Missing required field: name', 'name');
56
+ }
57
+ if (typeof this.name !== 'string') {
58
+ throw new ManifestError('name must be a string', 'name');
59
+ }
60
+ if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(this.name)) {
61
+ throw new ManifestError(
62
+ 'name must start with a letter and contain only letters, numbers, underscores, and hyphens',
63
+ 'name'
64
+ );
65
+ }
66
+
67
+ // Required: version
68
+ if (!this.version) {
69
+ throw new ManifestError('Missing required field: version', 'version');
70
+ }
71
+ if (!validVersion(this.version)) {
72
+ throw new ManifestError(`Invalid version: ${this.version}`, 'version');
73
+ }
74
+
75
+ // Optional: entry
76
+ if (this.entry && typeof this.entry !== 'string') {
77
+ throw new ManifestError('entry must be a string', 'entry');
78
+ }
79
+
80
+ // Optional: keywords
81
+ if (this.keywords && !Array.isArray(this.keywords)) {
82
+ throw new ManifestError('keywords must be an array', 'keywords');
83
+ }
84
+
85
+ // Validate dependencies
86
+ this.validateDependencies(this.dependencies, 'dependencies');
87
+ this.validateDependencies(this.devDependencies, 'devDependencies');
88
+
89
+ return true;
90
+ }
91
+
92
+ /**
93
+ * Validate a dependencies object
94
+ */
95
+ validateDependencies(deps, field) {
96
+ if (!deps || typeof deps !== 'object') return;
97
+
98
+ for (const [name, spec] of Object.entries(deps)) {
99
+ // Validate dependency name
100
+ if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(name)) {
101
+ throw new ManifestError(
102
+ `Invalid dependency name: ${name}`,
103
+ `${field}.${name}`
104
+ );
105
+ }
106
+
107
+ // Spec can be a string (version only) or object (version + source)
108
+ if (typeof spec === 'string') {
109
+ // Validate version range
110
+ try {
111
+ parseRange(spec);
112
+ } catch (e) {
113
+ throw new ManifestError(
114
+ `Invalid version range for ${name}: ${spec}`,
115
+ `${field}.${name}`
116
+ );
117
+ }
118
+ } else if (typeof spec === 'object' && spec !== null) {
119
+ // Must have version
120
+ if (!spec.version) {
121
+ throw new ManifestError(
122
+ `Missing version for dependency: ${name}`,
123
+ `${field}.${name}.version`
124
+ );
125
+ }
126
+ try {
127
+ parseRange(spec.version);
128
+ } catch (e) {
129
+ throw new ManifestError(
130
+ `Invalid version range for ${name}: ${spec.version}`,
131
+ `${field}.${name}.version`
132
+ );
133
+ }
134
+
135
+ // Optional source
136
+ if (spec.source && typeof spec.source !== 'string') {
137
+ throw new ManifestError(
138
+ `source must be a string for dependency: ${name}`,
139
+ `${field}.${name}.source`
140
+ );
141
+ }
142
+ } else {
143
+ throw new ManifestError(
144
+ `Invalid dependency specification for: ${name}`,
145
+ `${field}.${name}`
146
+ );
147
+ }
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Get normalized dependencies (always { version, source? })
153
+ */
154
+ getNormalizedDependencies() {
155
+ const result = {};
156
+
157
+ for (const [name, spec] of Object.entries(this.dependencies)) {
158
+ if (typeof spec === 'string') {
159
+ result[name] = { version: spec };
160
+ } else {
161
+ result[name] = { ...spec };
162
+ }
163
+ }
164
+
165
+ return result;
166
+ }
167
+
168
+ /**
169
+ * Add a dependency
170
+ */
171
+ addDependency(name, version, source = null) {
172
+ if (source) {
173
+ this.dependencies[name] = { version, source };
174
+ } else {
175
+ this.dependencies[name] = version;
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Remove a dependency
181
+ */
182
+ removeDependency(name) {
183
+ delete this.dependencies[name];
184
+ }
185
+
186
+ /**
187
+ * Check if a dependency exists
188
+ */
189
+ hasDependency(name) {
190
+ return name in this.dependencies;
191
+ }
192
+
193
+ /**
194
+ * Convert to plain object for serialization
195
+ */
196
+ toObject() {
197
+ const obj = {
198
+ name: this.name,
199
+ version: this.version,
200
+ };
201
+
202
+ if (this.entry && this.entry !== 'main.stn') {
203
+ obj.entry = this.entry;
204
+ }
205
+ if (this.description) {
206
+ obj.description = this.description;
207
+ }
208
+ if (this.author) {
209
+ obj.author = this.author;
210
+ }
211
+ if (this.license) {
212
+ obj.license = this.license;
213
+ }
214
+ if (this.keywords && this.keywords.length > 0) {
215
+ obj.keywords = this.keywords;
216
+ }
217
+ if (this.repository) {
218
+ obj.repository = this.repository;
219
+ }
220
+ if (Object.keys(this.dependencies).length > 0) {
221
+ obj.dependencies = this.dependencies;
222
+ }
223
+ if (Object.keys(this.devDependencies).length > 0) {
224
+ obj.devDependencies = this.devDependencies;
225
+ }
226
+
227
+ return obj;
228
+ }
229
+
230
+ /**
231
+ * Convert to .son string
232
+ */
233
+ toString() {
234
+ return stringifySON(this.toObject());
235
+ }
236
+ }
237
+
238
+ /**
239
+ * Parse a package.son file content
240
+ * @param {string} content - The file content
241
+ * @param {string} filename - Optional filename for error messages
242
+ * @returns {PackageManifest} Parsed manifest
243
+ */
244
+ export function parseManifest(content, filename = 'package.son') {
245
+ let data;
246
+
247
+ try {
248
+ data = parseSON(content, filename);
249
+ } catch (e) {
250
+ if (e instanceof SONParseError) {
251
+ throw new ManifestError(`Failed to parse ${filename}: ${e.message}`);
252
+ }
253
+ throw e;
254
+ }
255
+
256
+ const manifest = new PackageManifest(data);
257
+ manifest.validate();
258
+
259
+ return manifest;
260
+ }
261
+
262
+ /**
263
+ * Create a new manifest with default values
264
+ */
265
+ export function createManifest(name, version = '1.0.0') {
266
+ const manifest = new PackageManifest({
267
+ name,
268
+ version,
269
+ entry: 'main.stn',
270
+ });
271
+ manifest.validate();
272
+ return manifest;
273
+ }
274
+
275
+ /**
276
+ * Stringify a manifest to .son format
277
+ */
278
+ export function stringifyManifest(manifest) {
279
+ if (manifest instanceof PackageManifest) {
280
+ return manifest.toString();
281
+ }
282
+ return stringifySON(manifest);
283
+ }
284
+
285
+ export default {
286
+ PackageManifest,
287
+ ManifestError,
288
+ parseManifest,
289
+ createManifest,
290
+ stringifyManifest,
291
+ };