gofront 0.0.9 → 1.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.
Files changed (53) hide show
  1. package/README.md +5 -5
  2. package/package.json +7 -4
  3. package/src/cli-core.js +65 -0
  4. package/src/codegen/expressions.js +523 -1717
  5. package/src/codegen/index.js +576 -0
  6. package/src/codegen/runtime.js +151 -0
  7. package/src/codegen/statements.js +308 -296
  8. package/src/codegen/stdlib/builder.js +39 -0
  9. package/src/codegen/stdlib/bytes.js +65 -0
  10. package/src/codegen/stdlib/errors.js +20 -0
  11. package/src/codegen/stdlib/fmt.js +104 -0
  12. package/src/codegen/stdlib/gom.js +155 -0
  13. package/src/codegen/stdlib/html.js +20 -0
  14. package/src/codegen/stdlib/index.js +98 -0
  15. package/src/codegen/stdlib/io.js +36 -0
  16. package/src/codegen/stdlib/maps.js +45 -0
  17. package/src/codegen/stdlib/math.js +56 -0
  18. package/src/codegen/stdlib/os.js +13 -0
  19. package/src/codegen/stdlib/path.js +34 -0
  20. package/src/codegen/stdlib/rand.js +27 -0
  21. package/src/codegen/stdlib/regexp.js +54 -0
  22. package/src/codegen/stdlib/slices.js +51 -0
  23. package/src/codegen/stdlib/sort.js +31 -0
  24. package/src/codegen/stdlib/strconv.js +33 -0
  25. package/src/codegen/stdlib/strings.js +86 -0
  26. package/src/codegen/stdlib/time.js +57 -0
  27. package/src/codegen/stdlib/unicode.js +25 -0
  28. package/src/codegen/stdlib/utf8.js +26 -0
  29. package/src/codegen/templ.js +284 -0
  30. package/src/compiler.js +142 -77
  31. package/src/dts-parser.js +355 -371
  32. package/src/index.js +32 -162
  33. package/src/lexer.js +186 -272
  34. package/src/minifier.js +305 -318
  35. package/src/{parser.js → parser/declarations.js} +18 -175
  36. package/src/parser/expressions.js +51 -34
  37. package/src/parser/index.js +161 -0
  38. package/src/parser/statements.js +24 -34
  39. package/src/parser/types.js +31 -29
  40. package/src/templ-parser.js +2 -2
  41. package/src/tokens.js +109 -0
  42. package/src/typechecker/assignability.js +261 -0
  43. package/src/typechecker/expressions.js +568 -549
  44. package/src/typechecker/index.js +556 -0
  45. package/src/typechecker/resolve.js +428 -0
  46. package/src/typechecker/statements.js +270 -280
  47. package/src/typechecker/stdlib/core.js +592 -0
  48. package/src/typechecker/stdlib/extended.js +332 -0
  49. package/src/typechecker/stdlib.js +9 -1060
  50. package/src/typechecker/termination.js +86 -0
  51. package/src/typechecker/types.js +1 -0
  52. package/src/codegen.js +0 -882
  53. package/src/typechecker.js +0 -1299
@@ -1,159 +1,6 @@
1
- // Recursive-descent parser. Produces an AST from a GoFront token stream.
2
- //
3
- // Split into sub-modules under parser/:
4
- // types.js — type expression parsing (slice, map, struct, interface, etc.)
5
- // statements.js — block, control flow, simple statements
6
- // expressions.js — operator precedence, unary, postfix, primary, literals
7
- //
8
- // Node kinds used throughout the compiler:
9
- // Program, PackageDecl, ImportDecl
10
- // FuncDecl, MethodDecl, VarDecl, ConstDecl, TypeDecl
11
- // StructType, InterfaceType, SliceType, MapType, FuncType, PointerType
12
- // Block, IfStmt, ForStmt, RangeStmt, ReturnStmt, BranchStmt
13
- // AssignStmt, DefineStmt, IncDecStmt, ExprStmt
14
- // SwitchStmt, CaseClause
15
- // Ident, BasicLit, UnaryExpr, BinaryExpr
16
- // CallExpr, SelectorExpr, IndexExpr, SliceExpr
17
- // CompositeLit, KeyValueExpr, FuncLit, AwaitExpr
18
-
19
- import { T } from "./lexer.js";
20
- import { expressionParserMethods } from "./parser/expressions.js";
21
- import { statementParserMethods } from "./parser/statements.js";
22
- import { typeParserMethods } from "./parser/types.js";
23
-
24
- export class ParseError extends Error {
25
- constructor(msg, token, filename, sourceCode) {
26
- const loc = filename
27
- ? `${filename}:${token.line}:${token.col}`
28
- : `${token.line}:${token.col}`;
29
- let lineContext = "";
30
- if (token.line && sourceCode) {
31
- const lines = sourceCode.split("\n");
32
- const lineStr = lines[token.line - 1];
33
- if (lineStr !== undefined) {
34
- lineContext = `\n ${token.line} | ${lineStr}`;
35
- }
36
- }
37
- super(
38
- `Parse error at ${loc}: ${msg} (got ${token.type} "${token.value}")${lineContext}`,
39
- );
40
- this.token = token;
41
- }
42
- }
43
-
44
- export class Parser {
45
- constructor(tokens, filename = null, source = null) {
46
- this.tokens = tokens;
47
- this.pos = 0;
48
- this.filename = filename;
49
- this.source = source;
50
- }
51
-
52
- // ── Primitives ───────────────────────────────────────────────
53
-
54
- peek() {
55
- return this.tokens[this.pos];
56
- }
57
- peek2() {
58
- return this.tokens[this.pos + 1];
59
- }
60
-
61
- advance() {
62
- const t = this.tokens[this.pos];
63
- if (t.type !== T.EOF) this.pos++;
64
- return t;
65
- }
66
-
67
- check(type) {
68
- return this.peek().type === type;
69
- }
70
- check2(type) {
71
- return this.peek2().type === type;
72
- }
73
-
74
- match(...types) {
75
- for (const type of types) {
76
- if (this.check(type)) {
77
- this.advance();
78
- return true;
79
- }
80
- }
81
- return false;
82
- }
83
-
84
- expect(type) {
85
- if (!this.check(type))
86
- throw new ParseError(`expected '${type}'`, this.peek());
87
- return this.advance();
88
- }
89
-
90
- semi() {
91
- if (this.check(T.SEMICOLON)) this.advance();
92
- }
93
-
94
- err(msg) {
95
- throw new ParseError(msg, this.peek(), this.filename, this.source);
96
- }
97
-
98
- // ── Entry point ──────────────────────────────────────────────
99
-
100
- parse() {
101
- const pkg = this.parsePackage();
102
- const imports = [];
103
- while (this.check(T.IMPORT)) imports.push(this.parseImport());
104
- const decls = [];
105
- while (!this.check(T.EOF)) {
106
- const result = this.parseTopDecl();
107
- if (Array.isArray(result)) decls.push(...result);
108
- else decls.push(result);
109
- }
110
- return {
111
- kind: "Program",
112
- pkg,
113
- imports,
114
- decls,
115
- _filename: this.filename,
116
- _source: this.source,
117
- };
118
- }
119
-
120
- parsePackage() {
121
- this.expect(T.PACKAGE);
122
- const name = this.expect(T.IDENT).value;
123
- this.semi();
124
- return { kind: "PackageDecl", name };
125
- }
126
-
127
- parseImport() {
128
- this.expect(T.IMPORT);
129
- const imports = [];
130
- const parseOne = () => {
131
- const _line = this.peek().line;
132
- let alias = null;
133
- if (this.check(T.IDENT)) {
134
- alias = this.advance().value;
135
- } else if (this.check(T.DOT)) {
136
- alias = ".";
137
- this.advance();
138
- }
139
- const path = this.expect(T.STRING).value;
140
- return { path, alias, _line };
141
- };
142
- if (this.match(T.LPAREN)) {
143
- while (!this.check(T.RPAREN) && !this.check(T.EOF)) {
144
- imports.push(parseOne());
145
- this.semi();
146
- }
147
- this.expect(T.RPAREN);
148
- } else {
149
- imports.push(parseOne());
150
- }
151
- this.semi();
152
- return { kind: "ImportDecl", imports };
153
- }
154
-
155
- // ── Top-level declarations ───────────────────────────────────
1
+ import { T } from "../tokens.js";
156
2
 
3
+ export const declarationParseMethods = {
157
4
  parseTopDecl() {
158
5
  const t = this.peek();
159
6
  switch (t.type) {
@@ -170,7 +17,7 @@ export class Parser {
170
17
  default:
171
18
  this.err("Expected top-level declaration");
172
19
  }
173
- }
20
+ },
174
21
 
175
22
  parseFuncOrMethod() {
176
23
  const _line = this.peek().line;
@@ -219,14 +66,14 @@ export class Parser {
219
66
  body,
220
67
  _line,
221
68
  };
222
- }
69
+ },
223
70
 
224
71
  parseAsyncFuncOrMethod() {
225
72
  this.expect(T.ASYNC);
226
73
  const decl = this.parseFuncOrMethod();
227
74
  decl.async = true;
228
75
  return decl;
229
- }
76
+ },
230
77
 
231
78
  // Returns true if tok is a receiver-list terminator (i.e. not a type name)
232
79
  isReceiverTerminator(tok) {
@@ -237,7 +84,7 @@ export class Parser {
237
84
  tok.type === T.SEMICOLON ||
238
85
  tok.type === T.EOF)
239
86
  );
240
- }
87
+ },
241
88
 
242
89
  // Lookahead: does the [ ... ] after a func name or type name look like a type param list?
243
90
  // Type param lists contain IDENT followed by a constraint (another IDENT or keyword),
@@ -255,13 +102,13 @@ export class Parser {
255
102
  if (second.type === T.TILDE) return true; // T ~int
256
103
  if (second.type === T.INTERFACE) return true; // T interface{...}
257
104
  return false;
258
- }
105
+ },
259
106
 
260
107
  parseSignature() {
261
108
  const params = this.parseParamList();
262
109
  const returnType = this.parseReturnType();
263
110
  return { params, returnType };
264
- }
111
+ },
265
112
 
266
113
  // Parses (a, b int, c string) style param list
267
114
  parseParamList() {
@@ -296,7 +143,7 @@ export class Parser {
296
143
  }
297
144
  this.expect(T.RPAREN);
298
145
  return params;
299
- }
146
+ },
300
147
 
301
148
  // Lookahead: determine if current IDENT starts a named param (name type)
302
149
  // vs an unnamed param (just a type). Scans IDENT (COMMA IDENT)* and checks
@@ -313,7 +160,7 @@ export class Parser {
313
160
  const next = this.tokens[pos];
314
161
  if (!next) return false;
315
162
  return this.looksLikeType(next) || next.type === T.ELLIPSIS;
316
- }
163
+ },
317
164
 
318
165
  looksLikeType(tok) {
319
166
  return (
@@ -325,7 +172,7 @@ export class Parser {
325
172
  tok.type === T.STRUCT ||
326
173
  (tok.type === T.IDENT && tok.value !== "_")
327
174
  );
328
- }
175
+ },
329
176
 
330
177
  parseReturnType(inTypeExpr = false) {
331
178
  // No return type
@@ -367,7 +214,7 @@ export class Parser {
367
214
  return typeNode;
368
215
  }
369
216
  return this.parseType();
370
- }
217
+ },
371
218
 
372
219
  parseTypeDecl() {
373
220
  this.expect(T.TYPE);
@@ -394,7 +241,7 @@ export class Parser {
394
241
  const type = this.parseType();
395
242
  this.semi();
396
243
  return { kind: "TypeDecl", name, typeParams, type, isAlias };
397
- }
244
+ },
398
245
 
399
246
  parseVarDecl() {
400
247
  this.expect(T.VAR);
@@ -410,7 +257,7 @@ export class Parser {
410
257
  }
411
258
  this.semi();
412
259
  return { kind: "VarDecl", decls };
413
- }
260
+ },
414
261
 
415
262
  parseVarSpec() {
416
263
  const names = [this.expect(T.IDENT).value];
@@ -426,7 +273,7 @@ export class Parser {
426
273
  }
427
274
  if (this.match(T.ASSIGN)) value = this.parseExprList();
428
275
  return { names, type, value };
429
- }
276
+ },
430
277
 
431
278
  parseConstDecl() {
432
279
  this.expect(T.CONST);
@@ -477,7 +324,7 @@ export class Parser {
477
324
  }
478
325
  this.semi();
479
326
  return { kind: "ConstDecl", decls };
480
- }
327
+ },
481
328
 
482
329
  // Deep-clone an expression AST, replacing `iota` identifiers with the given integer.
483
330
  _substituteIota(node, val) {
@@ -496,9 +343,5 @@ export class Parser {
496
343
  }
497
344
  }
498
345
  return clone;
499
- }
500
- }
501
-
502
- Object.assign(Parser.prototype, typeParserMethods);
503
- Object.assign(Parser.prototype, statementParserMethods);
504
- Object.assign(Parser.prototype, expressionParserMethods);
346
+ },
347
+ };
@@ -1,6 +1,6 @@
1
1
  // Parser expression methods — installed as a mixin on Parser.prototype.
2
2
 
3
- import { T } from "../lexer.js";
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
  },
@@ -0,0 +1,161 @@
1
+ // Recursive-descent parser. Produces an AST from a GoFront token stream.
2
+ //
3
+ // Split into sub-modules under parser/:
4
+ // declarations.js — top-level declarations (func, method, type, var, const)
5
+ // types.js — type expression parsing (slice, map, struct, interface, etc.)
6
+ // statements.js — block, control flow, simple statements
7
+ // expressions.js — operator precedence, unary, postfix, primary, literals
8
+ //
9
+ // Node kinds used throughout the compiler:
10
+ // Program, PackageDecl, ImportDecl
11
+ // FuncDecl, MethodDecl, VarDecl, ConstDecl, TypeDecl
12
+ // StructType, InterfaceType, SliceType, MapType, FuncType, PointerType
13
+ // Block, IfStmt, ForStmt, RangeStmt, ReturnStmt, BranchStmt
14
+ // AssignStmt, DefineStmt, IncDecStmt, ExprStmt
15
+ // SwitchStmt, CaseClause
16
+ // Ident, BasicLit, UnaryExpr, BinaryExpr
17
+ // CallExpr, SelectorExpr, IndexExpr, SliceExpr
18
+ // CompositeLit, KeyValueExpr, FuncLit, AwaitExpr
19
+
20
+ import { T } from "../tokens.js";
21
+ import { declarationParseMethods } from "./declarations.js";
22
+ import { expressionParserMethods } from "./expressions.js";
23
+ import { statementParserMethods } from "./statements.js";
24
+ import { typeParserMethods } from "./types.js";
25
+
26
+ export class ParseError extends Error {
27
+ constructor(msg, token, filename, sourceCode) {
28
+ const loc = filename
29
+ ? `${filename}:${token.line}:${token.col}`
30
+ : `${token.line}:${token.col}`;
31
+ let lineContext = "";
32
+ if (token.line && sourceCode) {
33
+ const lines = sourceCode.split("\n");
34
+ const lineStr = lines[token.line - 1];
35
+ if (lineStr !== undefined) {
36
+ lineContext = `\n ${token.line} | ${lineStr}`;
37
+ }
38
+ }
39
+ super(
40
+ `Parse error at ${loc}: ${msg} (got ${token.type} "${token.value}")${lineContext}`,
41
+ );
42
+ this.token = token;
43
+ }
44
+ }
45
+
46
+ export class Parser {
47
+ constructor(tokens, filename = null, source = null) {
48
+ this.tokens = tokens;
49
+ this.pos = 0;
50
+ this.filename = filename;
51
+ this.source = source;
52
+ }
53
+
54
+ // ── Primitives ───────────────────────────────────────────────
55
+
56
+ peek() {
57
+ return this.tokens[this.pos];
58
+ }
59
+ peek2() {
60
+ return this.tokens[this.pos + 1];
61
+ }
62
+
63
+ advance() {
64
+ const t = this.tokens[this.pos];
65
+ if (t.type !== T.EOF) this.pos++;
66
+ return t;
67
+ }
68
+
69
+ check(type) {
70
+ return this.peek().type === type;
71
+ }
72
+ check2(type) {
73
+ return this.peek2().type === type;
74
+ }
75
+
76
+ match(...types) {
77
+ for (const type of types) {
78
+ if (this.check(type)) {
79
+ this.advance();
80
+ return true;
81
+ }
82
+ }
83
+ return false;
84
+ }
85
+
86
+ expect(type) {
87
+ if (!this.check(type))
88
+ throw new ParseError(`expected '${type}'`, this.peek());
89
+ return this.advance();
90
+ }
91
+
92
+ semi() {
93
+ if (this.check(T.SEMICOLON)) this.advance();
94
+ }
95
+
96
+ err(msg) {
97
+ throw new ParseError(msg, this.peek(), this.filename, this.source);
98
+ }
99
+
100
+ // ── Entry point ──────────────────────────────────────────────
101
+
102
+ parse() {
103
+ const pkg = this.parsePackage();
104
+ const imports = [];
105
+ while (this.check(T.IMPORT)) imports.push(this.parseImport());
106
+ const decls = [];
107
+ while (!this.check(T.EOF)) {
108
+ const result = this.parseTopDecl();
109
+ if (Array.isArray(result)) decls.push(...result);
110
+ else decls.push(result);
111
+ }
112
+ return {
113
+ kind: "Program",
114
+ pkg,
115
+ imports,
116
+ decls,
117
+ _filename: this.filename,
118
+ _source: this.source,
119
+ };
120
+ }
121
+
122
+ parsePackage() {
123
+ this.expect(T.PACKAGE);
124
+ const name = this.expect(T.IDENT).value;
125
+ this.semi();
126
+ return { kind: "PackageDecl", name };
127
+ }
128
+
129
+ parseImport() {
130
+ this.expect(T.IMPORT);
131
+ const imports = [];
132
+ const parseOne = () => {
133
+ const _line = this.peek().line;
134
+ let alias = null;
135
+ if (this.check(T.IDENT)) {
136
+ alias = this.advance().value;
137
+ } else if (this.check(T.DOT)) {
138
+ alias = ".";
139
+ this.advance();
140
+ }
141
+ const path = this.expect(T.STRING).value;
142
+ return { path, alias, _line };
143
+ };
144
+ if (this.match(T.LPAREN)) {
145
+ while (!this.check(T.RPAREN) && !this.check(T.EOF)) {
146
+ imports.push(parseOne());
147
+ this.semi();
148
+ }
149
+ this.expect(T.RPAREN);
150
+ } else {
151
+ imports.push(parseOne());
152
+ }
153
+ this.semi();
154
+ return { kind: "ImportDecl", imports };
155
+ }
156
+ }
157
+
158
+ Object.assign(Parser.prototype, typeParserMethods);
159
+ Object.assign(Parser.prototype, statementParserMethods);
160
+ Object.assign(Parser.prototype, expressionParserMethods);
161
+ Object.assign(Parser.prototype, declarationParseMethods);
@@ -1,6 +1,19 @@
1
1
  // Parser statement methods — installed as a mixin on Parser.prototype.
2
2
 
3
- import { T } from "../lexer.js";
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() {
@@ -32,59 +45,36 @@ export const statementParserMethods = {
32
45
  },
33
46
 
34
47
  _parseStmt(t) {
48
+ const delegate = PARSE_STMT_DELEGATE[t.type];
49
+ if (delegate) return this[delegate]();
50
+
35
51
  switch (t.type) {
36
- case T.VAR:
37
- return this.parseVarDecl();
38
- case T.CONST:
39
- return this.parseConstDecl();
40
- case T.TYPE:
41
- return this.parseTypeDecl();
42
- case T.RETURN:
43
- return this.parseReturn();
44
- case T.DEFER:
45
- return this.parseDefer();
46
52
  case T.BREAK:
47
- this.advance();
48
- if (this.check(T.IDENT)) {
49
- const label = this.advance().value;
50
- this.semi();
51
- return { kind: "BranchStmt", keyword: "break", label };
52
- }
53
- this.semi();
54
- return { kind: "BranchStmt", keyword: "break" };
55
- case T.CONTINUE:
56
- this.advance();
53
+ case T.CONTINUE: {
54
+ const keyword = this.advance().value;
57
55
  if (this.check(T.IDENT)) {
58
56
  const label = this.advance().value;
59
57
  this.semi();
60
- return { kind: "BranchStmt", keyword: "continue", label };
58
+ return { kind: "BranchStmt", keyword, label };
61
59
  }
62
60
  this.semi();
63
- return { kind: "BranchStmt", keyword: "continue" };
61
+ return { kind: "BranchStmt", keyword };
62
+ }
64
63
  case T.FALLTHROUGH:
65
64
  this.advance();
66
65
  this.semi();
67
66
  return { kind: "BranchStmt", keyword: "fallthrough" };
68
- case T.IF:
69
- return this.parseIf();
70
- case T.FOR:
71
- return this.parseFor();
72
- case T.SWITCH:
73
- return this.parseSwitch();
74
67
  case T.GO:
75
68
  return this.err("goroutines are not supported in GoFront");
76
69
  case T.SELECT:
77
70
  return this.err(
78
71
  "select statement is not supported in GoFront (no channels)",
79
72
  );
80
- case T.LBRACE:
81
- return this.parseBlock();
82
73
  case T.IDENT:
83
74
  if (this.check2(T.COLON)) {
84
- const label = this.advance().value; // consume IDENT
75
+ const label = this.advance().value;
85
76
  this.advance(); // consume COLON
86
- const body = this.parseStmt();
87
- return { kind: "LabeledStmt", label, body };
77
+ return { kind: "LabeledStmt", label, body: this.parseStmt() };
88
78
  }
89
79
  return this.parseSimpleStmt();
90
80
  default: