gofront 0.0.5 → 0.0.7
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 +104 -37
- package/package.json +7 -4
- package/src/codegen/expressions.js +589 -7
- package/src/codegen/source-map.js +13 -5
- package/src/codegen/statements.js +30 -26
- package/src/codegen.js +99 -22
- package/src/compiler.js +10 -3
- package/src/dev-server.js +83 -0
- package/src/index.js +35 -5
- package/src/parser.js +0 -10
- package/src/typechecker/expressions.js +38 -9
- package/src/typechecker/stdlib.js +764 -0
- package/src/typechecker/types.js +15 -20
- package/src/typechecker.js +34 -394
package/src/typechecker/types.js
CHANGED
|
@@ -101,13 +101,22 @@ export function isGeneric(t) {
|
|
|
101
101
|
return t?.kind === "generic";
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
104
|
+
function makeBasicPredicate(...names) {
|
|
105
|
+
const set = new Set(names);
|
|
106
|
+
const pred = (t) => {
|
|
107
|
+
if (!t) return false;
|
|
108
|
+
if (t.kind === "untyped") return set.has(t.base);
|
|
109
|
+
if (t.kind === "basic") return set.has(t.name);
|
|
110
|
+
if (t.kind === "named") return pred(t.underlying);
|
|
111
|
+
return false;
|
|
112
|
+
};
|
|
113
|
+
return pred;
|
|
110
114
|
}
|
|
115
|
+
|
|
116
|
+
export const isNumeric = makeBasicPredicate("int", "float64");
|
|
117
|
+
export const isString = makeBasicPredicate("string");
|
|
118
|
+
export const isBool = makeBasicPredicate("bool");
|
|
119
|
+
|
|
111
120
|
export function isComplex(t) {
|
|
112
121
|
if (!t) return false;
|
|
113
122
|
if (t.kind === "basic" && (t.name === "complex128" || t.name === "complex64"))
|
|
@@ -119,20 +128,6 @@ export function isComplex(t) {
|
|
|
119
128
|
export function isComplexOrNumeric(t) {
|
|
120
129
|
return isNumeric(t) || isComplex(t);
|
|
121
130
|
}
|
|
122
|
-
export function isString(t) {
|
|
123
|
-
if (!t) return false;
|
|
124
|
-
if (t.kind === "untyped") return t.base === "string";
|
|
125
|
-
if (t.kind === "basic") return t.name === "string";
|
|
126
|
-
if (t.kind === "named") return isString(t.underlying);
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
export function isBool(t) {
|
|
130
|
-
if (!t) return false;
|
|
131
|
-
if (t.kind === "untyped") return t.base === "bool";
|
|
132
|
-
if (t.kind === "basic") return t.name === "bool";
|
|
133
|
-
if (t.kind === "named") return isBool(t.underlying);
|
|
134
|
-
return false;
|
|
135
|
-
}
|
|
136
131
|
export function isAny(t) {
|
|
137
132
|
return t?.kind === "basic" && t.name === "any";
|
|
138
133
|
}
|
package/src/typechecker.js
CHANGED
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
//
|
|
4
4
|
// Split into sub-modules under typechecker/:
|
|
5
5
|
// types.js — shared type constants, predicates, Scope
|
|
6
|
+
// stdlib.js — browser globals + all built-in package registrations
|
|
6
7
|
// statements.js — checkBlock, checkStmt
|
|
7
8
|
// expressions.js — checkExpr, checkCall, checkBuiltin, checkCompositeLit
|
|
8
9
|
|
|
9
10
|
import { expressionCheckMethods } from "./typechecker/expressions.js";
|
|
10
11
|
import { statementCheckMethods } from "./typechecker/statements.js";
|
|
12
|
+
import { setupGlobals } from "./typechecker/stdlib.js";
|
|
11
13
|
import {
|
|
12
14
|
ANY,
|
|
13
15
|
BASIC_TYPES,
|
|
@@ -59,396 +61,7 @@ export class TypeChecker {
|
|
|
59
61
|
}
|
|
60
62
|
|
|
61
63
|
_setupGlobals() {
|
|
62
|
-
|
|
63
|
-
const browserGlobals = [
|
|
64
|
-
"console",
|
|
65
|
-
"document",
|
|
66
|
-
"window",
|
|
67
|
-
"navigator",
|
|
68
|
-
"location",
|
|
69
|
-
"history",
|
|
70
|
-
"screen",
|
|
71
|
-
"performance",
|
|
72
|
-
"crypto",
|
|
73
|
-
"indexedDB",
|
|
74
|
-
"fetch",
|
|
75
|
-
"setTimeout",
|
|
76
|
-
"setInterval",
|
|
77
|
-
"clearTimeout",
|
|
78
|
-
"clearInterval",
|
|
79
|
-
"requestAnimationFrame",
|
|
80
|
-
"cancelAnimationFrame",
|
|
81
|
-
"Math",
|
|
82
|
-
"JSON",
|
|
83
|
-
"Date",
|
|
84
|
-
"RegExp",
|
|
85
|
-
"Promise",
|
|
86
|
-
"Error",
|
|
87
|
-
"Symbol",
|
|
88
|
-
"String",
|
|
89
|
-
"Number",
|
|
90
|
-
"Boolean",
|
|
91
|
-
"Array",
|
|
92
|
-
"Object",
|
|
93
|
-
"parseInt",
|
|
94
|
-
"parseFloat",
|
|
95
|
-
"isNaN",
|
|
96
|
-
"isFinite",
|
|
97
|
-
"encodeURIComponent",
|
|
98
|
-
"decodeURIComponent",
|
|
99
|
-
"atob",
|
|
100
|
-
"btoa",
|
|
101
|
-
"alert",
|
|
102
|
-
"confirm",
|
|
103
|
-
"prompt",
|
|
104
|
-
"localStorage",
|
|
105
|
-
"sessionStorage",
|
|
106
|
-
"WebSocket",
|
|
107
|
-
"Worker",
|
|
108
|
-
"HTMLElement",
|
|
109
|
-
"Element",
|
|
110
|
-
"Event",
|
|
111
|
-
"CustomEvent",
|
|
112
|
-
"URL",
|
|
113
|
-
"URLSearchParams",
|
|
114
|
-
"FormData",
|
|
115
|
-
"Headers",
|
|
116
|
-
"Request",
|
|
117
|
-
"Response",
|
|
118
|
-
"Blob",
|
|
119
|
-
"File",
|
|
120
|
-
"FileReader",
|
|
121
|
-
"ArrayBuffer",
|
|
122
|
-
"Uint8Array",
|
|
123
|
-
"TextEncoder",
|
|
124
|
-
"TextDecoder",
|
|
125
|
-
"WebGLRenderingContext",
|
|
126
|
-
"WebGL2RenderingContext",
|
|
127
|
-
"GPUDevice",
|
|
128
|
-
"GPUAdapter",
|
|
129
|
-
];
|
|
130
|
-
for (const g of browserGlobals) this.globals.define(g, ANY);
|
|
131
|
-
|
|
132
|
-
// Built-in functions
|
|
133
|
-
// fmt package — string formatting (variadic: format string + any args)
|
|
134
|
-
const fmtVariadic = (ret) => ({
|
|
135
|
-
kind: "func",
|
|
136
|
-
params: [STRING, ANY],
|
|
137
|
-
returns: [ret],
|
|
138
|
-
variadic: true,
|
|
139
|
-
});
|
|
140
|
-
this.globals.define("fmt", {
|
|
141
|
-
kind: "namespace",
|
|
142
|
-
name: "fmt",
|
|
143
|
-
members: {
|
|
144
|
-
Sprintf: fmtVariadic(STRING),
|
|
145
|
-
Errorf: fmtVariadic(ERROR),
|
|
146
|
-
Printf: fmtVariadic(VOID),
|
|
147
|
-
Println: fmtVariadic(VOID),
|
|
148
|
-
Print: fmtVariadic(VOID),
|
|
149
|
-
},
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
// strings package
|
|
153
|
-
const strFn1 = (ret) => ({
|
|
154
|
-
kind: "func",
|
|
155
|
-
params: [STRING],
|
|
156
|
-
returns: [ret],
|
|
157
|
-
});
|
|
158
|
-
const strFn2 = (p2, ret) => ({
|
|
159
|
-
kind: "func",
|
|
160
|
-
params: [STRING, p2],
|
|
161
|
-
returns: [ret],
|
|
162
|
-
});
|
|
163
|
-
const strFn3 = (p2, p3, ret) => ({
|
|
164
|
-
kind: "func",
|
|
165
|
-
params: [STRING, p2, p3],
|
|
166
|
-
returns: [ret],
|
|
167
|
-
});
|
|
168
|
-
this.globals.define("strings", {
|
|
169
|
-
kind: "namespace",
|
|
170
|
-
name: "strings",
|
|
171
|
-
members: {
|
|
172
|
-
Contains: strFn2(STRING, BOOL),
|
|
173
|
-
HasPrefix: strFn2(STRING, BOOL),
|
|
174
|
-
HasSuffix: strFn2(STRING, BOOL),
|
|
175
|
-
Index: strFn2(STRING, INT),
|
|
176
|
-
LastIndex: strFn2(STRING, INT),
|
|
177
|
-
Count: strFn2(STRING, INT),
|
|
178
|
-
Repeat: strFn2(INT, STRING),
|
|
179
|
-
Replace: {
|
|
180
|
-
kind: "func",
|
|
181
|
-
params: [STRING, STRING, STRING, INT],
|
|
182
|
-
returns: [STRING],
|
|
183
|
-
},
|
|
184
|
-
ReplaceAll: strFn3(STRING, STRING, STRING),
|
|
185
|
-
ToUpper: strFn1(STRING),
|
|
186
|
-
ToLower: strFn1(STRING),
|
|
187
|
-
TrimSpace: strFn1(STRING),
|
|
188
|
-
Trim: strFn2(STRING, STRING),
|
|
189
|
-
TrimPrefix: strFn2(STRING, STRING),
|
|
190
|
-
TrimSuffix: strFn2(STRING, STRING),
|
|
191
|
-
TrimLeft: strFn2(STRING, STRING),
|
|
192
|
-
TrimRight: strFn2(STRING, STRING),
|
|
193
|
-
Split: strFn2(STRING, { kind: "slice", elem: STRING }),
|
|
194
|
-
Join: {
|
|
195
|
-
kind: "func",
|
|
196
|
-
params: [{ kind: "slice", elem: STRING }, STRING],
|
|
197
|
-
returns: [STRING],
|
|
198
|
-
},
|
|
199
|
-
EqualFold: strFn2(STRING, BOOL),
|
|
200
|
-
},
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
// bytes package — operates on []byte (JS arrays of numbers)
|
|
204
|
-
const BYTE_SLICE = { kind: "slice", elem: INT };
|
|
205
|
-
const byFn1 = (ret) => ({
|
|
206
|
-
kind: "func",
|
|
207
|
-
params: [BYTE_SLICE],
|
|
208
|
-
returns: [ret],
|
|
209
|
-
});
|
|
210
|
-
const byFn2 = (p2, ret) => ({
|
|
211
|
-
kind: "func",
|
|
212
|
-
params: [BYTE_SLICE, p2],
|
|
213
|
-
returns: [ret],
|
|
214
|
-
});
|
|
215
|
-
this.globals.define("bytes", {
|
|
216
|
-
kind: "namespace",
|
|
217
|
-
name: "bytes",
|
|
218
|
-
members: {
|
|
219
|
-
Contains: byFn2(BYTE_SLICE, BOOL),
|
|
220
|
-
HasPrefix: byFn2(BYTE_SLICE, BOOL),
|
|
221
|
-
HasSuffix: byFn2(BYTE_SLICE, BOOL),
|
|
222
|
-
Index: byFn2(BYTE_SLICE, INT),
|
|
223
|
-
Count: byFn2(BYTE_SLICE, INT),
|
|
224
|
-
Repeat: byFn2(INT, BYTE_SLICE),
|
|
225
|
-
Replace: {
|
|
226
|
-
kind: "func",
|
|
227
|
-
params: [BYTE_SLICE, BYTE_SLICE, BYTE_SLICE, INT],
|
|
228
|
-
returns: [BYTE_SLICE],
|
|
229
|
-
},
|
|
230
|
-
ToUpper: byFn1(BYTE_SLICE),
|
|
231
|
-
ToLower: byFn1(BYTE_SLICE),
|
|
232
|
-
TrimSpace: byFn1(BYTE_SLICE),
|
|
233
|
-
Trim: byFn2(STRING, BYTE_SLICE),
|
|
234
|
-
Equal: byFn2(BYTE_SLICE, BOOL),
|
|
235
|
-
Split: byFn2(BYTE_SLICE, { kind: "slice", elem: BYTE_SLICE }),
|
|
236
|
-
Join: {
|
|
237
|
-
kind: "func",
|
|
238
|
-
params: [{ kind: "slice", elem: BYTE_SLICE }, BYTE_SLICE],
|
|
239
|
-
returns: [BYTE_SLICE],
|
|
240
|
-
},
|
|
241
|
-
},
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
// strconv package
|
|
245
|
-
this.globals.define("strconv", {
|
|
246
|
-
kind: "namespace",
|
|
247
|
-
name: "strconv",
|
|
248
|
-
members: {
|
|
249
|
-
Itoa: { kind: "func", params: [INT], returns: [STRING] },
|
|
250
|
-
Atoi: {
|
|
251
|
-
kind: "func",
|
|
252
|
-
params: [STRING],
|
|
253
|
-
returns: [INT, ERROR],
|
|
254
|
-
},
|
|
255
|
-
FormatFloat: {
|
|
256
|
-
kind: "func",
|
|
257
|
-
params: [FLOAT64, INT, INT, INT],
|
|
258
|
-
returns: [STRING],
|
|
259
|
-
},
|
|
260
|
-
FormatBool: { kind: "func", params: [BOOL], returns: [STRING] },
|
|
261
|
-
FormatInt: { kind: "func", params: [INT, INT], returns: [STRING] },
|
|
262
|
-
ParseFloat: {
|
|
263
|
-
kind: "func",
|
|
264
|
-
params: [STRING, INT],
|
|
265
|
-
returns: [FLOAT64, ERROR],
|
|
266
|
-
},
|
|
267
|
-
ParseInt: {
|
|
268
|
-
kind: "func",
|
|
269
|
-
params: [STRING, INT, INT],
|
|
270
|
-
returns: [INT, ERROR],
|
|
271
|
-
},
|
|
272
|
-
ParseBool: {
|
|
273
|
-
kind: "func",
|
|
274
|
-
params: [STRING],
|
|
275
|
-
returns: [BOOL, ERROR],
|
|
276
|
-
},
|
|
277
|
-
},
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
// sort package
|
|
281
|
-
this.globals.define("sort", {
|
|
282
|
-
kind: "namespace",
|
|
283
|
-
name: "sort",
|
|
284
|
-
members: {
|
|
285
|
-
Ints: {
|
|
286
|
-
kind: "func",
|
|
287
|
-
params: [{ kind: "slice", elem: INT }],
|
|
288
|
-
returns: [VOID],
|
|
289
|
-
},
|
|
290
|
-
Float64s: {
|
|
291
|
-
kind: "func",
|
|
292
|
-
params: [{ kind: "slice", elem: FLOAT64 }],
|
|
293
|
-
returns: [VOID],
|
|
294
|
-
},
|
|
295
|
-
Strings: {
|
|
296
|
-
kind: "func",
|
|
297
|
-
params: [{ kind: "slice", elem: STRING }],
|
|
298
|
-
returns: [VOID],
|
|
299
|
-
},
|
|
300
|
-
Slice: {
|
|
301
|
-
kind: "func",
|
|
302
|
-
params: [ANY, ANY],
|
|
303
|
-
returns: [VOID],
|
|
304
|
-
},
|
|
305
|
-
SliceStable: {
|
|
306
|
-
kind: "func",
|
|
307
|
-
params: [ANY, ANY],
|
|
308
|
-
returns: [VOID],
|
|
309
|
-
},
|
|
310
|
-
SliceIsSorted: {
|
|
311
|
-
kind: "func",
|
|
312
|
-
params: [ANY, ANY],
|
|
313
|
-
returns: [BOOL],
|
|
314
|
-
},
|
|
315
|
-
},
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
// math package
|
|
319
|
-
this.globals.define("math", {
|
|
320
|
-
kind: "namespace",
|
|
321
|
-
name: "math",
|
|
322
|
-
members: {
|
|
323
|
-
Abs: { kind: "func", params: [FLOAT64], returns: [FLOAT64] },
|
|
324
|
-
Floor: { kind: "func", params: [FLOAT64], returns: [FLOAT64] },
|
|
325
|
-
Ceil: { kind: "func", params: [FLOAT64], returns: [FLOAT64] },
|
|
326
|
-
Round: { kind: "func", params: [FLOAT64], returns: [FLOAT64] },
|
|
327
|
-
Sqrt: { kind: "func", params: [FLOAT64], returns: [FLOAT64] },
|
|
328
|
-
Cbrt: { kind: "func", params: [FLOAT64], returns: [FLOAT64] },
|
|
329
|
-
Pow: {
|
|
330
|
-
kind: "func",
|
|
331
|
-
params: [FLOAT64, FLOAT64],
|
|
332
|
-
returns: [FLOAT64],
|
|
333
|
-
},
|
|
334
|
-
Log: { kind: "func", params: [FLOAT64], returns: [FLOAT64] },
|
|
335
|
-
Log2: { kind: "func", params: [FLOAT64], returns: [FLOAT64] },
|
|
336
|
-
Log10: { kind: "func", params: [FLOAT64], returns: [FLOAT64] },
|
|
337
|
-
Sin: { kind: "func", params: [FLOAT64], returns: [FLOAT64] },
|
|
338
|
-
Cos: { kind: "func", params: [FLOAT64], returns: [FLOAT64] },
|
|
339
|
-
Tan: { kind: "func", params: [FLOAT64], returns: [FLOAT64] },
|
|
340
|
-
Min: {
|
|
341
|
-
kind: "func",
|
|
342
|
-
params: [FLOAT64, FLOAT64],
|
|
343
|
-
returns: [FLOAT64],
|
|
344
|
-
},
|
|
345
|
-
Max: {
|
|
346
|
-
kind: "func",
|
|
347
|
-
params: [FLOAT64, FLOAT64],
|
|
348
|
-
returns: [FLOAT64],
|
|
349
|
-
},
|
|
350
|
-
Mod: {
|
|
351
|
-
kind: "func",
|
|
352
|
-
params: [FLOAT64, FLOAT64],
|
|
353
|
-
returns: [FLOAT64],
|
|
354
|
-
},
|
|
355
|
-
Inf: { kind: "func", params: [INT], returns: [FLOAT64] },
|
|
356
|
-
IsNaN: { kind: "func", params: [FLOAT64], returns: [BOOL] },
|
|
357
|
-
IsInf: {
|
|
358
|
-
kind: "func",
|
|
359
|
-
params: [FLOAT64, INT],
|
|
360
|
-
returns: [BOOL],
|
|
361
|
-
},
|
|
362
|
-
NaN: { kind: "func", params: [], returns: [FLOAT64] },
|
|
363
|
-
// Constants (typed as func with no params for namespace member access)
|
|
364
|
-
Pi: FLOAT64,
|
|
365
|
-
E: FLOAT64,
|
|
366
|
-
MaxFloat64: FLOAT64,
|
|
367
|
-
SmallestNonzeroFloat64: FLOAT64,
|
|
368
|
-
MaxInt: INT,
|
|
369
|
-
MinInt: INT,
|
|
370
|
-
},
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
// errors package
|
|
374
|
-
this.globals.define("errors", {
|
|
375
|
-
kind: "namespace",
|
|
376
|
-
name: "errors",
|
|
377
|
-
members: {
|
|
378
|
-
New: { kind: "func", params: [STRING], returns: [ERROR] },
|
|
379
|
-
Is: { kind: "func", params: [ERROR, ERROR], returns: [BOOL] },
|
|
380
|
-
Unwrap: { kind: "func", params: [ERROR], returns: [ERROR] },
|
|
381
|
-
},
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
// time package (partial — JS-friendly subset)
|
|
385
|
-
this.globals.define("time", {
|
|
386
|
-
kind: "namespace",
|
|
387
|
-
name: "time",
|
|
388
|
-
members: {
|
|
389
|
-
Now: { kind: "func", params: [], returns: [ANY] },
|
|
390
|
-
Since: { kind: "func", params: [ANY], returns: [ANY] },
|
|
391
|
-
Sleep: { kind: "func", params: [ANY], returns: [VOID], async: true },
|
|
392
|
-
Millisecond: INT,
|
|
393
|
-
Second: INT,
|
|
394
|
-
Minute: INT,
|
|
395
|
-
Hour: INT,
|
|
396
|
-
},
|
|
397
|
-
});
|
|
398
|
-
|
|
399
|
-
// unicode package
|
|
400
|
-
const runeToStr = { kind: "func", params: [INT], returns: [BOOL] };
|
|
401
|
-
const runeTrans = { kind: "func", params: [INT], returns: [INT] };
|
|
402
|
-
this.globals.define("unicode", {
|
|
403
|
-
kind: "namespace",
|
|
404
|
-
name: "unicode",
|
|
405
|
-
members: {
|
|
406
|
-
IsLetter: runeToStr,
|
|
407
|
-
IsDigit: runeToStr,
|
|
408
|
-
IsSpace: runeToStr,
|
|
409
|
-
IsUpper: runeToStr,
|
|
410
|
-
IsLower: runeToStr,
|
|
411
|
-
IsPunct: runeToStr,
|
|
412
|
-
IsControl: runeToStr,
|
|
413
|
-
IsPrint: runeToStr,
|
|
414
|
-
IsGraphic: runeToStr,
|
|
415
|
-
ToUpper: runeTrans,
|
|
416
|
-
ToLower: runeTrans,
|
|
417
|
-
},
|
|
418
|
-
});
|
|
419
|
-
|
|
420
|
-
// os package (JS-friendly subset)
|
|
421
|
-
this.globals.define("os", {
|
|
422
|
-
kind: "namespace",
|
|
423
|
-
name: "os",
|
|
424
|
-
members: {
|
|
425
|
-
Exit: { kind: "func", params: [INT], returns: [VOID] },
|
|
426
|
-
Args: { kind: "slice", elem: STRING },
|
|
427
|
-
Getenv: { kind: "func", params: [STRING], returns: [STRING] },
|
|
428
|
-
Stdout: ANY,
|
|
429
|
-
Stderr: ANY,
|
|
430
|
-
Stdin: ANY,
|
|
431
|
-
},
|
|
432
|
-
});
|
|
433
|
-
|
|
434
|
-
this.globals.define("append", { kind: "builtin", name: "append" });
|
|
435
|
-
this.globals.define("len", { kind: "builtin", name: "len" });
|
|
436
|
-
this.globals.define("cap", { kind: "builtin", name: "cap" });
|
|
437
|
-
this.globals.define("make", { kind: "builtin", name: "make" });
|
|
438
|
-
this.globals.define("delete", { kind: "builtin", name: "delete" });
|
|
439
|
-
this.globals.define("print", { kind: "builtin", name: "print" });
|
|
440
|
-
this.globals.define("println", { kind: "builtin", name: "println" });
|
|
441
|
-
this.globals.define("panic", { kind: "builtin", name: "panic" });
|
|
442
|
-
this.globals.define("recover", { kind: "builtin", name: "recover" });
|
|
443
|
-
this.globals.define("new", { kind: "builtin", name: "new" });
|
|
444
|
-
this.globals.define("copy", { kind: "builtin", name: "copy" });
|
|
445
|
-
this.globals.define("error", { kind: "builtin", name: "error" });
|
|
446
|
-
this.globals.define("min", { kind: "builtin", name: "min" });
|
|
447
|
-
this.globals.define("max", { kind: "builtin", name: "max" });
|
|
448
|
-
this.globals.define("clear", { kind: "builtin", name: "clear" });
|
|
449
|
-
this.globals.define("complex", { kind: "builtin", name: "complex" });
|
|
450
|
-
this.globals.define("real", { kind: "builtin", name: "real" });
|
|
451
|
-
this.globals.define("imag", { kind: "builtin", name: "imag" });
|
|
64
|
+
setupGlobals(this.globals, this.types);
|
|
452
65
|
}
|
|
453
66
|
|
|
454
67
|
addDefinitions(types, values) {
|
|
@@ -473,7 +86,10 @@ export class TypeChecker {
|
|
|
473
86
|
members,
|
|
474
87
|
_gofront: true,
|
|
475
88
|
});
|
|
476
|
-
for (const [name, type] of types)
|
|
89
|
+
for (const [name, type] of types) {
|
|
90
|
+
this.types.set(name, type);
|
|
91
|
+
this.types.set(`${pkgName}.${name}`, type);
|
|
92
|
+
}
|
|
477
93
|
}
|
|
478
94
|
|
|
479
95
|
// Register an import for unused-import detection.
|
|
@@ -677,6 +293,8 @@ export class TypeChecker {
|
|
|
677
293
|
if (underlying.kind === "struct") {
|
|
678
294
|
underlying.name = decl.name;
|
|
679
295
|
underlying.methods = new Map();
|
|
296
|
+
} else if (underlying.kind !== "interface") {
|
|
297
|
+
named.methods = new Map();
|
|
680
298
|
}
|
|
681
299
|
if (underlying.kind === "interface") {
|
|
682
300
|
underlying.name = decl.name;
|
|
@@ -745,7 +363,7 @@ export class TypeChecker {
|
|
|
745
363
|
this.globals.define(decl.name, funcType);
|
|
746
364
|
}
|
|
747
365
|
} else {
|
|
748
|
-
// Method: attach to struct type
|
|
366
|
+
// Method: attach to struct or named non-struct type
|
|
749
367
|
const recvTypeName =
|
|
750
368
|
decl.recvType.kind === "GenericTypeName"
|
|
751
369
|
? decl.recvType.name
|
|
@@ -765,6 +383,8 @@ export class TypeChecker {
|
|
|
765
383
|
const base = recvType?.underlying ?? recvType;
|
|
766
384
|
if (base?.kind === "struct") {
|
|
767
385
|
base.methods.set(decl.name, funcType);
|
|
386
|
+
} else if (recvType?.kind === "named" && recvType.methods) {
|
|
387
|
+
recvType.methods.set(decl.name, funcType);
|
|
768
388
|
}
|
|
769
389
|
}
|
|
770
390
|
}
|
|
@@ -1360,6 +980,19 @@ export class TypeChecker {
|
|
|
1360
980
|
fieldType(baseType, field, node) {
|
|
1361
981
|
baseType = this.resolveType(baseType);
|
|
1362
982
|
if (!baseType || isAny(baseType)) return ANY;
|
|
983
|
+
// Transparent pointer dereference for named-type method calls: (*T).Method works like T.Method
|
|
984
|
+
// (only unwrap when the pointer's base is a named type that has methods)
|
|
985
|
+
if (
|
|
986
|
+
baseType.kind === "pointer" &&
|
|
987
|
+
field !== "value" &&
|
|
988
|
+
baseType.base?.kind === "named"
|
|
989
|
+
) {
|
|
990
|
+
baseType = this.resolveType(baseType.base);
|
|
991
|
+
}
|
|
992
|
+
// Check methods on named type itself (for non-struct named types)
|
|
993
|
+
if (baseType.kind === "named" && baseType.methods?.has(field)) {
|
|
994
|
+
return baseType.methods.get(field);
|
|
995
|
+
}
|
|
1363
996
|
let base = baseType.kind === "named" ? baseType.underlying : baseType;
|
|
1364
997
|
base = this.resolveType(base);
|
|
1365
998
|
if (base?.kind === "struct") {
|
|
@@ -1597,9 +1230,16 @@ export class TypeChecker {
|
|
|
1597
1230
|
implements(srcType, iface, _node) {
|
|
1598
1231
|
let base = srcType.kind === "named" ? srcType.underlying : srcType;
|
|
1599
1232
|
base = this.resolveType(base);
|
|
1600
|
-
|
|
1233
|
+
// For non-struct named types, methods live on the named type itself
|
|
1234
|
+
const methodMap =
|
|
1235
|
+
base?.kind === "struct"
|
|
1236
|
+
? base.methods
|
|
1237
|
+
: srcType.kind === "named"
|
|
1238
|
+
? srcType.methods
|
|
1239
|
+
: null;
|
|
1240
|
+
if (!methodMap) return false;
|
|
1601
1241
|
for (const [name, required] of iface.methods) {
|
|
1602
|
-
const actual =
|
|
1242
|
+
const actual = methodMap.get(name);
|
|
1603
1243
|
if (!actual) return false;
|
|
1604
1244
|
|
|
1605
1245
|
// Check parameter count matches
|