naider 2.0.0 → 2.0.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.
- package/README.md +105 -29
- package/bin/naide.js +471 -25
- package/lsp/server.js +210 -100
- package/mcp/server.js +246 -21
- package/package.json +7 -2
- package/src/generator-c.js +34 -14
- package/src/generator-go.js +26 -0
- package/src/project-tools.js +785 -0
- package/src/typechecker.js +87 -5
- package/vscode-naide/README.md +1 -1
- package/vscode-naide/package-lock.json +2 -2
- package/vscode-naide/package.json +1 -1
package/src/typechecker.js
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
|
+
const EXPRESSION_TYPES = new Set([
|
|
2
|
+
'Number', 'String', 'InterpolatedString', 'Bool', 'Null', 'Array', 'Object',
|
|
3
|
+
'Identifier', 'Binary', 'Unary', 'Call', 'MemberAccess', 'Ternary', 'Await',
|
|
4
|
+
'ArrowFunction', 'Spread', 'New', 'IndexAccess',
|
|
5
|
+
]);
|
|
6
|
+
|
|
1
7
|
export class TypeChecker {
|
|
2
8
|
constructor() {
|
|
3
9
|
this.scopes = [new Map()];
|
|
4
10
|
this.errors = [];
|
|
5
11
|
this.warnings = [];
|
|
12
|
+
this.errorKeys = new Set();
|
|
13
|
+
this.warningKeys = new Set();
|
|
14
|
+
this.visitedStatements = new WeakSet();
|
|
6
15
|
this.functions = new Map();
|
|
7
16
|
this.returnTypes = [];
|
|
8
17
|
}
|
|
@@ -22,11 +31,19 @@ export class TypeChecker {
|
|
|
22
31
|
}
|
|
23
32
|
|
|
24
33
|
error(msg, line) {
|
|
25
|
-
|
|
34
|
+
const diagnostic = { message: msg, line: line || 0, severity: 'error' };
|
|
35
|
+
const key = `${diagnostic.line}:${diagnostic.message}`;
|
|
36
|
+
if (this.errorKeys.has(key)) return;
|
|
37
|
+
this.errorKeys.add(key);
|
|
38
|
+
this.errors.push(diagnostic);
|
|
26
39
|
}
|
|
27
40
|
|
|
28
41
|
warn(msg, line) {
|
|
29
|
-
|
|
42
|
+
const diagnostic = { message: msg, line: line || 0, severity: 'warning' };
|
|
43
|
+
const key = `${diagnostic.line}:${diagnostic.message}`;
|
|
44
|
+
if (this.warningKeys.has(key)) return;
|
|
45
|
+
this.warningKeys.add(key);
|
|
46
|
+
this.warnings.push(diagnostic);
|
|
30
47
|
}
|
|
31
48
|
|
|
32
49
|
check(ast) {
|
|
@@ -52,7 +69,10 @@ export class TypeChecker {
|
|
|
52
69
|
}
|
|
53
70
|
|
|
54
71
|
visitStatement(node) {
|
|
72
|
+
if (this.visitedStatements.has(node)) return;
|
|
73
|
+
this.visitedStatements.add(node);
|
|
55
74
|
const line = node._line || 0;
|
|
75
|
+
this.checkExpressions(node);
|
|
56
76
|
switch (node.type) {
|
|
57
77
|
case 'TypedVar': return this.visitTypedVar(node, line);
|
|
58
78
|
case 'Function': return this.visitFunction(node, line);
|
|
@@ -63,11 +83,59 @@ export class TypeChecker {
|
|
|
63
83
|
case 'For': return this.visitFor(node, line);
|
|
64
84
|
case 'While': return this.visitWhile(node, line);
|
|
65
85
|
case 'Try': return this.visitTry(node, line);
|
|
66
|
-
case 'Server': return this.
|
|
67
|
-
default: return;
|
|
86
|
+
case 'Server': return this.visitServer(node, line);
|
|
87
|
+
default: return this.visitNestedStatements(node);
|
|
68
88
|
}
|
|
69
89
|
}
|
|
70
90
|
|
|
91
|
+
checkExpressions(node) {
|
|
92
|
+
const seen = new WeakSet();
|
|
93
|
+
const visit = value => {
|
|
94
|
+
if (Array.isArray(value)) {
|
|
95
|
+
if (seen.has(value)) return;
|
|
96
|
+
seen.add(value);
|
|
97
|
+
for (const item of value) visit(item);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (!value || typeof value !== 'object') return;
|
|
101
|
+
if (seen.has(value)) return;
|
|
102
|
+
seen.add(value);
|
|
103
|
+
|
|
104
|
+
if (typeof value.type === 'string') {
|
|
105
|
+
if (!EXPRESSION_TYPES.has(value.type)) return;
|
|
106
|
+
this.inferType(value);
|
|
107
|
+
for (const [key, child] of Object.entries(value)) {
|
|
108
|
+
if (key !== 'type' && key !== '_line') visit(child);
|
|
109
|
+
}
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
for (const child of Object.values(value)) visit(child);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
for (const [key, value] of Object.entries(node)) {
|
|
117
|
+
if (key !== 'type' && key !== '_line') visit(value);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
visitNestedStatements(value, seen = new WeakSet()) {
|
|
122
|
+
if (Array.isArray(value)) {
|
|
123
|
+
if (seen.has(value)) return;
|
|
124
|
+
seen.add(value);
|
|
125
|
+
for (const item of value) this.visitNestedStatements(item, seen);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (!value || typeof value !== 'object') return;
|
|
129
|
+
if (seen.has(value)) return;
|
|
130
|
+
seen.add(value);
|
|
131
|
+
if (typeof value.type === 'string') {
|
|
132
|
+
if (EXPRESSION_TYPES.has(value.type)) return;
|
|
133
|
+
this.visitStatement(value);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
for (const child of Object.values(value)) this.visitNestedStatements(child, seen);
|
|
137
|
+
}
|
|
138
|
+
|
|
71
139
|
visitBlock(body, _line) {
|
|
72
140
|
if (!body) return;
|
|
73
141
|
this.pushScope();
|
|
@@ -99,6 +167,7 @@ export class TypeChecker {
|
|
|
99
167
|
this.pushScope();
|
|
100
168
|
for (const p of node.params) {
|
|
101
169
|
this.setType(p.name, p.type || 'any');
|
|
170
|
+
if (p.defaultValue) this.inferType(p.defaultValue);
|
|
102
171
|
}
|
|
103
172
|
this.returnTypes.push(node.returnType || 'any');
|
|
104
173
|
for (const stmt of node.body) {
|
|
@@ -188,6 +257,19 @@ export class TypeChecker {
|
|
|
188
257
|
}
|
|
189
258
|
}
|
|
190
259
|
|
|
260
|
+
visitServer(node, line) {
|
|
261
|
+
for (const route of node.routes || []) {
|
|
262
|
+
this.pushScope();
|
|
263
|
+
for (const param of route.params || []) {
|
|
264
|
+
this.setType(typeof param === 'string' ? param : param.name, 'any');
|
|
265
|
+
}
|
|
266
|
+
this.visitBlock(route.body, line);
|
|
267
|
+
this.popScope();
|
|
268
|
+
}
|
|
269
|
+
this.visitNestedStatements(node.middleware || []);
|
|
270
|
+
this.visitNestedStatements(node.body || []);
|
|
271
|
+
}
|
|
272
|
+
|
|
191
273
|
inferType(node) {
|
|
192
274
|
if (!node) return 'any';
|
|
193
275
|
switch (node.type) {
|
|
@@ -197,7 +279,7 @@ export class TypeChecker {
|
|
|
197
279
|
}
|
|
198
280
|
case 'String': return 'str';
|
|
199
281
|
case 'InterpolatedString': return 'str';
|
|
200
|
-
case '
|
|
282
|
+
case 'Bool': return 'bool';
|
|
201
283
|
case 'Null': return 'any';
|
|
202
284
|
case 'Array': return 'list';
|
|
203
285
|
case 'Object': return 'map';
|
package/vscode-naide/README.md
CHANGED
|
@@ -24,7 +24,7 @@ Syntax highlighting and language support for **NAIDE** (`.naide`) files.
|
|
|
24
24
|
cd vscode-naide
|
|
25
25
|
npm install -g @vscode/vsce
|
|
26
26
|
vsce package
|
|
27
|
-
code --install-extension naide-lang-2.0.
|
|
27
|
+
code --install-extension naide-lang-2.0.1.vsix
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
### Manual
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "naide-lang",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "naide-lang",
|
|
9
|
-
"version": "2.0.
|
|
9
|
+
"version": "2.0.1",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"vscode-languageclient": "^9.0.0"
|
|
12
12
|
},
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "naide-lang",
|
|
3
3
|
"displayName": "NAIDE Language",
|
|
4
4
|
"description": "Syntax highlighting, diagnostics, and autocomplete for NAIDE (.naide)",
|
|
5
|
-
"version": "2.0.
|
|
5
|
+
"version": "2.0.1",
|
|
6
6
|
"publisher": "irxk",
|
|
7
7
|
"engines": { "vscode": "^1.75.0" },
|
|
8
8
|
"categories": ["Programming Languages"],
|