gofront 0.0.8 → 1.0.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 +88 -12
- package/package.json +8 -4
- package/src/codegen/expressions.js +520 -1717
- package/src/{codegen.js → codegen/index.js} +155 -184
- package/src/codegen/runtime.js +151 -0
- package/src/codegen/statements.js +305 -296
- package/src/codegen/stdlib/builder.js +36 -0
- package/src/codegen/stdlib/bytes.js +62 -0
- package/src/codegen/stdlib/errors.js +17 -0
- package/src/codegen/stdlib/fmt.js +101 -0
- package/src/codegen/stdlib/gom.js +152 -0
- package/src/codegen/stdlib/html.js +17 -0
- package/src/codegen/stdlib/index.js +95 -0
- package/src/codegen/stdlib/io.js +33 -0
- package/src/codegen/stdlib/maps.js +42 -0
- package/src/codegen/stdlib/math.js +53 -0
- package/src/codegen/stdlib/os.js +10 -0
- package/src/codegen/stdlib/path.js +31 -0
- package/src/codegen/stdlib/rand.js +24 -0
- package/src/codegen/stdlib/regexp.js +51 -0
- package/src/codegen/stdlib/slices.js +48 -0
- package/src/codegen/stdlib/sort.js +28 -0
- package/src/codegen/stdlib/strconv.js +30 -0
- package/src/codegen/stdlib/strings.js +83 -0
- package/src/codegen/stdlib/time.js +54 -0
- package/src/codegen/stdlib/unicode.js +22 -0
- package/src/codegen/stdlib/utf8.js +23 -0
- package/src/codegen/templ.js +281 -0
- package/src/compiler.js +102 -62
- package/src/dts-parser.js +355 -371
- package/src/index.js +22 -54
- package/src/lexer.js +200 -286
- package/src/minifier.js +305 -318
- package/src/parser/expressions.js +54 -36
- package/src/{parser.js → parser/index.js} +12 -5
- package/src/parser/statements.js +29 -35
- package/src/parser/types.js +31 -29
- package/src/templ-lexer.js +737 -0
- package/src/templ-parser.js +235 -0
- package/src/tokens.js +109 -0
- package/src/typechecker/assignability.js +258 -0
- package/src/typechecker/expressions.js +559 -549
- package/src/typechecker/index.js +555 -0
- package/src/typechecker/resolve.js +421 -0
- package/src/typechecker/statements.js +267 -280
- package/src/typechecker/stdlib/core.js +592 -0
- package/src/typechecker/stdlib/extended.js +332 -0
- package/src/typechecker/stdlib.js +9 -1060
- package/src/typechecker/termination.js +83 -0
- package/src/typechecker/types.js +6 -3
- package/src/typechecker.js +0 -1271
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Parser expression methods — installed as a mixin on Parser.prototype.
|
|
2
2
|
|
|
3
|
-
import { T } from "../
|
|
3
|
+
import { T } from "../tokens.js";
|
|
4
4
|
|
|
5
5
|
// Binary operator precedence (higher = binds tighter, matching Go spec)
|
|
6
6
|
const PREC = {
|
|
@@ -55,6 +55,45 @@ const BUILTIN_KEYWORDS = new Set([
|
|
|
55
55
|
"imag",
|
|
56
56
|
]);
|
|
57
57
|
|
|
58
|
+
// Tokens that cannot legally appear inside a type argument list.
|
|
59
|
+
// Each || in an inline condition counts as CC; extracting here keeps looksLikeTypeArgList lean.
|
|
60
|
+
const DISALLOWED_IN_TYPE_ARGS = new Set([
|
|
61
|
+
T.PLUS,
|
|
62
|
+
T.MINUS,
|
|
63
|
+
T.PERCENT,
|
|
64
|
+
T.SLASH,
|
|
65
|
+
T.AND,
|
|
66
|
+
T.OR,
|
|
67
|
+
T.CARET,
|
|
68
|
+
T.NOT,
|
|
69
|
+
T.LT,
|
|
70
|
+
T.GT,
|
|
71
|
+
T.LTE,
|
|
72
|
+
T.GTE,
|
|
73
|
+
T.EQ,
|
|
74
|
+
T.NEQ,
|
|
75
|
+
T.LSHIFT,
|
|
76
|
+
T.RSHIFT,
|
|
77
|
+
T.AND_NOT,
|
|
78
|
+
T.COLON,
|
|
79
|
+
T.DEFINE,
|
|
80
|
+
T.ASSIGN,
|
|
81
|
+
]);
|
|
82
|
+
|
|
83
|
+
function _isDisallowedInTypeArgs(tt) {
|
|
84
|
+
return DISALLOWED_IN_TYPE_ARGS.has(tt);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function _isTypeIntroducerToken(tt) {
|
|
88
|
+
return (
|
|
89
|
+
tt === T.STAR ||
|
|
90
|
+
tt === T.MAP ||
|
|
91
|
+
tt === T.FUNC ||
|
|
92
|
+
tt === T.INTERFACE ||
|
|
93
|
+
tt === T.STRUCT
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
58
97
|
export const expressionParserMethods = {
|
|
59
98
|
parseExprList() {
|
|
60
99
|
const exprs = [this.parseExpr()];
|
|
@@ -185,6 +224,7 @@ export const expressionParserMethods = {
|
|
|
185
224
|
let depth = 1;
|
|
186
225
|
let hasComma = false;
|
|
187
226
|
let hasTypeKeyword = false;
|
|
227
|
+
let hasUpperIdent = false;
|
|
188
228
|
while (i < src.length && depth > 0) {
|
|
189
229
|
const tt = src[i].type;
|
|
190
230
|
if (tt === T.LBRACKET) {
|
|
@@ -201,42 +241,19 @@ export const expressionParserMethods = {
|
|
|
201
241
|
// Reject literals — it's an index expression
|
|
202
242
|
if (tt === T.INT || tt === T.FLOAT || tt === T.STRING) return false;
|
|
203
243
|
// Reject binary operators that wouldn't appear in type args
|
|
204
|
-
if (
|
|
205
|
-
tt === T.PLUS ||
|
|
206
|
-
tt === T.MINUS ||
|
|
207
|
-
tt === T.PERCENT ||
|
|
208
|
-
tt === T.SLASH ||
|
|
209
|
-
tt === T.AND ||
|
|
210
|
-
tt === T.OR ||
|
|
211
|
-
tt === T.CARET ||
|
|
212
|
-
tt === T.NOT ||
|
|
213
|
-
tt === T.LT ||
|
|
214
|
-
tt === T.GT ||
|
|
215
|
-
tt === T.LTE ||
|
|
216
|
-
tt === T.GTE ||
|
|
217
|
-
tt === T.EQ ||
|
|
218
|
-
tt === T.NEQ ||
|
|
219
|
-
tt === T.LSHIFT ||
|
|
220
|
-
tt === T.RSHIFT ||
|
|
221
|
-
tt === T.AND_NOT ||
|
|
222
|
-
tt === T.COLON ||
|
|
223
|
-
tt === T.DEFINE ||
|
|
224
|
-
tt === T.ASSIGN
|
|
225
|
-
)
|
|
226
|
-
return false;
|
|
244
|
+
if (_isDisallowedInTypeArgs(tt)) return false;
|
|
227
245
|
if (depth === 1) {
|
|
228
246
|
if (tt === T.COMMA) hasComma = true;
|
|
229
|
-
if (
|
|
230
|
-
tt === T.STAR ||
|
|
231
|
-
tt === T.MAP ||
|
|
232
|
-
tt === T.FUNC ||
|
|
233
|
-
tt === T.INTERFACE ||
|
|
234
|
-
tt === T.STRUCT
|
|
235
|
-
)
|
|
236
|
-
hasTypeKeyword = true;
|
|
237
|
-
// Check if it's a builtin type name
|
|
247
|
+
if (_isTypeIntroducerToken(tt)) hasTypeKeyword = true;
|
|
238
248
|
if (tt === T.IDENT && TYPE_KEYWORDS.has(src[i].value))
|
|
239
249
|
hasTypeKeyword = true;
|
|
250
|
+
// User-defined types start with uppercase (GoFront convention)
|
|
251
|
+
if (
|
|
252
|
+
tt === T.IDENT &&
|
|
253
|
+
/^[A-Z]/.test(src[i].value) &&
|
|
254
|
+
!TYPE_KEYWORDS.has(src[i].value)
|
|
255
|
+
)
|
|
256
|
+
hasUpperIdent = true;
|
|
240
257
|
}
|
|
241
258
|
i++;
|
|
242
259
|
}
|
|
@@ -248,7 +265,7 @@ export const expressionParserMethods = {
|
|
|
248
265
|
if (after.type === T.LPAREN || after.type === T.LBRACE) return true;
|
|
249
266
|
// Function value in argument list: Identity[int], 99) — only if clearly a type
|
|
250
267
|
if (after.type === T.COMMA || after.type === T.RPAREN) {
|
|
251
|
-
return hasComma || hasTypeKeyword;
|
|
268
|
+
return hasComma || hasTypeKeyword || hasUpperIdent;
|
|
252
269
|
}
|
|
253
270
|
return false;
|
|
254
271
|
},
|
|
@@ -365,9 +382,10 @@ export const expressionParserMethods = {
|
|
|
365
382
|
},
|
|
366
383
|
|
|
367
384
|
parsePrimary() {
|
|
368
|
-
const
|
|
385
|
+
const t = this.peek();
|
|
369
386
|
const expr = this._parsePrimary();
|
|
370
|
-
if (!expr._line) expr._line = line;
|
|
387
|
+
if (!expr._line) expr._line = t.line;
|
|
388
|
+
if (!expr._col) expr._col = t.col;
|
|
371
389
|
return expr;
|
|
372
390
|
},
|
|
373
391
|
|
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
// CallExpr, SelectorExpr, IndexExpr, SliceExpr
|
|
17
17
|
// CompositeLit, KeyValueExpr, FuncLit, AwaitExpr
|
|
18
18
|
|
|
19
|
-
import { T } from "
|
|
20
|
-
import { expressionParserMethods } from "./
|
|
21
|
-
import { statementParserMethods } from "./
|
|
22
|
-
import { typeParserMethods } from "./
|
|
19
|
+
import { T } from "../tokens.js";
|
|
20
|
+
import { expressionParserMethods } from "./expressions.js";
|
|
21
|
+
import { statementParserMethods } from "./statements.js";
|
|
22
|
+
import { typeParserMethods } from "./types.js";
|
|
23
23
|
|
|
24
24
|
export class ParseError extends Error {
|
|
25
25
|
constructor(msg, token, filename, sourceCode) {
|
|
@@ -107,7 +107,14 @@ export class Parser {
|
|
|
107
107
|
if (Array.isArray(result)) decls.push(...result);
|
|
108
108
|
else decls.push(result);
|
|
109
109
|
}
|
|
110
|
-
return {
|
|
110
|
+
return {
|
|
111
|
+
kind: "Program",
|
|
112
|
+
pkg,
|
|
113
|
+
imports,
|
|
114
|
+
decls,
|
|
115
|
+
_filename: this.filename,
|
|
116
|
+
_source: this.source,
|
|
117
|
+
};
|
|
111
118
|
}
|
|
112
119
|
|
|
113
120
|
parsePackage() {
|
package/src/parser/statements.js
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
// Parser statement methods — installed as a mixin on Parser.prototype.
|
|
2
2
|
|
|
3
|
-
import { T } from "../
|
|
3
|
+
import { T } from "../tokens.js";
|
|
4
|
+
|
|
5
|
+
// Method-name dispatch for pure-delegation cases in _parseStmt.
|
|
6
|
+
const PARSE_STMT_DELEGATE = {
|
|
7
|
+
[T.VAR]: "parseVarDecl",
|
|
8
|
+
[T.CONST]: "parseConstDecl",
|
|
9
|
+
[T.TYPE]: "parseTypeDecl",
|
|
10
|
+
[T.RETURN]: "parseReturn",
|
|
11
|
+
[T.DEFER]: "parseDefer",
|
|
12
|
+
[T.IF]: "parseIf",
|
|
13
|
+
[T.FOR]: "parseFor",
|
|
14
|
+
[T.SWITCH]: "parseSwitch",
|
|
15
|
+
[T.LBRACE]: "parseBlock",
|
|
16
|
+
};
|
|
4
17
|
|
|
5
18
|
export const statementParserMethods = {
|
|
6
19
|
parseBlock() {
|
|
@@ -20,67 +33,48 @@ export const statementParserMethods = {
|
|
|
20
33
|
const t = this.peek();
|
|
21
34
|
const stmt = this._parseStmt(t);
|
|
22
35
|
if (Array.isArray(stmt)) {
|
|
23
|
-
for (const s of stmt)
|
|
36
|
+
for (const s of stmt) {
|
|
37
|
+
s._line = t.line;
|
|
38
|
+
s._col = t.col;
|
|
39
|
+
}
|
|
24
40
|
return stmt;
|
|
25
41
|
}
|
|
26
42
|
stmt._line = t.line;
|
|
43
|
+
stmt._col = t.col;
|
|
27
44
|
return stmt;
|
|
28
45
|
},
|
|
29
46
|
|
|
30
47
|
_parseStmt(t) {
|
|
48
|
+
const delegate = PARSE_STMT_DELEGATE[t.type];
|
|
49
|
+
if (delegate) return this[delegate]();
|
|
50
|
+
|
|
31
51
|
switch (t.type) {
|
|
32
|
-
case T.VAR:
|
|
33
|
-
return this.parseVarDecl();
|
|
34
|
-
case T.CONST:
|
|
35
|
-
return this.parseConstDecl();
|
|
36
|
-
case T.TYPE:
|
|
37
|
-
return this.parseTypeDecl();
|
|
38
|
-
case T.RETURN:
|
|
39
|
-
return this.parseReturn();
|
|
40
|
-
case T.DEFER:
|
|
41
|
-
return this.parseDefer();
|
|
42
52
|
case T.BREAK:
|
|
43
|
-
|
|
53
|
+
case T.CONTINUE: {
|
|
54
|
+
const keyword = this.advance().value;
|
|
44
55
|
if (this.check(T.IDENT)) {
|
|
45
56
|
const label = this.advance().value;
|
|
46
57
|
this.semi();
|
|
47
|
-
return { kind: "BranchStmt", keyword
|
|
58
|
+
return { kind: "BranchStmt", keyword, label };
|
|
48
59
|
}
|
|
49
60
|
this.semi();
|
|
50
|
-
return { kind: "BranchStmt", keyword
|
|
51
|
-
|
|
52
|
-
this.advance();
|
|
53
|
-
if (this.check(T.IDENT)) {
|
|
54
|
-
const label = this.advance().value;
|
|
55
|
-
this.semi();
|
|
56
|
-
return { kind: "BranchStmt", keyword: "continue", label };
|
|
57
|
-
}
|
|
58
|
-
this.semi();
|
|
59
|
-
return { kind: "BranchStmt", keyword: "continue" };
|
|
61
|
+
return { kind: "BranchStmt", keyword };
|
|
62
|
+
}
|
|
60
63
|
case T.FALLTHROUGH:
|
|
61
64
|
this.advance();
|
|
62
65
|
this.semi();
|
|
63
66
|
return { kind: "BranchStmt", keyword: "fallthrough" };
|
|
64
|
-
case T.IF:
|
|
65
|
-
return this.parseIf();
|
|
66
|
-
case T.FOR:
|
|
67
|
-
return this.parseFor();
|
|
68
|
-
case T.SWITCH:
|
|
69
|
-
return this.parseSwitch();
|
|
70
67
|
case T.GO:
|
|
71
68
|
return this.err("goroutines are not supported in GoFront");
|
|
72
69
|
case T.SELECT:
|
|
73
70
|
return this.err(
|
|
74
71
|
"select statement is not supported in GoFront (no channels)",
|
|
75
72
|
);
|
|
76
|
-
case T.LBRACE:
|
|
77
|
-
return this.parseBlock();
|
|
78
73
|
case T.IDENT:
|
|
79
74
|
if (this.check2(T.COLON)) {
|
|
80
|
-
const label = this.advance().value;
|
|
75
|
+
const label = this.advance().value;
|
|
81
76
|
this.advance(); // consume COLON
|
|
82
|
-
|
|
83
|
-
return { kind: "LabeledStmt", label, body };
|
|
77
|
+
return { kind: "LabeledStmt", label, body: this.parseStmt() };
|
|
84
78
|
}
|
|
85
79
|
return this.parseSimpleStmt();
|
|
86
80
|
default:
|
package/src/parser/types.js
CHANGED
|
@@ -1,39 +1,41 @@
|
|
|
1
1
|
// Parser type-expression methods — installed as a mixin on Parser.prototype.
|
|
2
2
|
|
|
3
|
-
import { T } from "../
|
|
3
|
+
import { T } from "../tokens.js";
|
|
4
|
+
|
|
5
|
+
// Token types that directly map to parseTypeName().
|
|
6
|
+
const TYPE_NAME_TOKENS = new Set([
|
|
7
|
+
T.IDENT,
|
|
8
|
+
"int",
|
|
9
|
+
"float64",
|
|
10
|
+
"string",
|
|
11
|
+
"bool",
|
|
12
|
+
"any",
|
|
13
|
+
"byte",
|
|
14
|
+
"rune",
|
|
15
|
+
"error",
|
|
16
|
+
]);
|
|
17
|
+
// Method-name dispatch for the simple keyword cases in parseType().
|
|
18
|
+
const PARSE_TYPE_DELEGATE = {
|
|
19
|
+
[T.LBRACKET]: "parseSliceOrArrayType",
|
|
20
|
+
[T.MAP]: "parseMapType",
|
|
21
|
+
[T.FUNC]: "parseFuncType",
|
|
22
|
+
[T.STRUCT]: "parseStructType",
|
|
23
|
+
[T.INTERFACE]: "parseInterfaceType",
|
|
24
|
+
};
|
|
4
25
|
|
|
5
26
|
export const typeParserMethods = {
|
|
6
27
|
parseType() {
|
|
7
28
|
const t = this.peek();
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
return this.parseFuncType();
|
|
15
|
-
case T.STRUCT:
|
|
16
|
-
return this.parseStructType();
|
|
17
|
-
case T.INTERFACE:
|
|
18
|
-
return this.parseInterfaceType();
|
|
19
|
-
case T.STAR:
|
|
20
|
-
this.advance();
|
|
21
|
-
return { kind: "PointerType", base: this.parseType() };
|
|
22
|
-
case T.CHAN:
|
|
23
|
-
return this.err("channels are not supported in GoFront");
|
|
24
|
-
case T.IDENT:
|
|
25
|
-
case "int":
|
|
26
|
-
case "float64":
|
|
27
|
-
case "string":
|
|
28
|
-
case "bool":
|
|
29
|
-
case "any":
|
|
30
|
-
case "byte":
|
|
31
|
-
case "rune":
|
|
32
|
-
case "error":
|
|
33
|
-
return this.parseTypeName();
|
|
34
|
-
default:
|
|
35
|
-
this.err(`Expected type, got '${t.value}'`);
|
|
29
|
+
const delegate = PARSE_TYPE_DELEGATE[t.type];
|
|
30
|
+
if (delegate) return this[delegate]();
|
|
31
|
+
if (TYPE_NAME_TOKENS.has(t.type)) return this.parseTypeName();
|
|
32
|
+
if (t.type === T.STAR) {
|
|
33
|
+
this.advance();
|
|
34
|
+
return { kind: "PointerType", base: this.parseType() };
|
|
36
35
|
}
|
|
36
|
+
if (t.type === T.CHAN)
|
|
37
|
+
return this.err("channels are not supported in GoFront");
|
|
38
|
+
return this.err(`Expected type, got '${t.value}'`);
|
|
37
39
|
},
|
|
38
40
|
|
|
39
41
|
parseTypeName() {
|