gofront 0.0.1 → 0.0.3
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 +357 -33
- package/package.json +7 -3
- package/src/codegen/expressions.js +804 -0
- package/src/codegen/source-map.js +45 -0
- package/src/codegen/statements.js +406 -0
- package/src/codegen.js +50 -851
- package/src/compiler.js +44 -23
- package/src/dts-parser.js +0 -4
- package/src/index.js +11 -20
- package/src/lexer.js +170 -12
- package/src/parser/expressions.js +389 -0
- package/src/parser/statements.js +355 -0
- package/src/parser/types.js +140 -0
- package/src/parser.js +57 -745
- package/src/resolver.js +1 -1
- package/src/typechecker/expressions.js +359 -0
- package/src/typechecker/statements.js +250 -0
- package/src/typechecker/types.js +226 -0
- package/src/typechecker.js +390 -647
package/src/compiler.js
CHANGED
|
@@ -86,8 +86,9 @@ export function compileFiles(files, options = {}) {
|
|
|
86
86
|
|
|
87
87
|
// js: prefix — local .d.ts files
|
|
88
88
|
for (const imp of allImports) {
|
|
89
|
-
for (const path of imp.
|
|
89
|
+
for (const { path, alias } of imp.imports) {
|
|
90
90
|
if (!path.startsWith("js:")) continue;
|
|
91
|
+
if (alias === "_") continue; // side-effect import — no type definitions
|
|
91
92
|
const dtsPath = join(fromDir, path.slice(3));
|
|
92
93
|
try {
|
|
93
94
|
const { types, values } = parseDts(readFileSync(dtsPath, "utf8"));
|
|
@@ -98,8 +99,12 @@ export function compileFiles(files, options = {}) {
|
|
|
98
99
|
}
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
// npm packages
|
|
102
|
-
const
|
|
102
|
+
// npm packages — exclude side-effect imports (alias "_") from type resolution
|
|
103
|
+
const allImportsNoSideEffect = allImports.map((imp) => ({
|
|
104
|
+
...imp,
|
|
105
|
+
imports: imp.imports.filter(({ alias }) => alias !== "_"),
|
|
106
|
+
}));
|
|
107
|
+
const resolved = resolveAll(allImportsNoSideEffect, dummyFromFile, parseDts);
|
|
103
108
|
for (const [path, info] of resolved) {
|
|
104
109
|
if (!info) continue;
|
|
105
110
|
checker.addDefinitions(info.types, info.values);
|
|
@@ -108,33 +113,49 @@ export function compileFiles(files, options = {}) {
|
|
|
108
113
|
|
|
109
114
|
// local GoFront packages (./subdir)
|
|
110
115
|
const seenLocalPaths = new Set();
|
|
111
|
-
for (const
|
|
112
|
-
for (const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
116
|
+
for (const p of programs) {
|
|
117
|
+
for (const imp of p.imports) {
|
|
118
|
+
for (const { path, alias, _line } of imp.imports) {
|
|
119
|
+
if (!isLocalPath(path) || seenLocalPaths.has(path)) continue;
|
|
120
|
+
seenLocalPaths.add(path);
|
|
121
|
+
|
|
122
|
+
const depDir = resolveGwDir(path, dummyFromFile);
|
|
123
|
+
if (!depDir) {
|
|
124
|
+
console.error(
|
|
125
|
+
`gofront: warning: cannot find local package '${path}' relative to ${fromDir}`,
|
|
126
|
+
);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Recursively compile dependency
|
|
131
|
+
const dep = compileDir(depDir);
|
|
132
|
+
preambles.push(dep.js);
|
|
133
|
+
if (alias === "_") continue; // side-effect import — bundle code but don't expose namespace
|
|
134
|
+
|
|
135
|
+
// Dot import: flatten all exported symbols into global scope
|
|
136
|
+
if (alias === ".") {
|
|
137
|
+
checker.addDefinitions(dep.exportedTypes, dep.exportedSymbols);
|
|
138
|
+
// All dep symbols must be treated as bundled so codegen
|
|
139
|
+
// can emit them without a qualifier. We DON'T add a
|
|
140
|
+
// namespace, so SelectorExpr never appears for these.
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const nameUsed = alias ?? dep.pkgName;
|
|
145
|
+
bundledPackages.add(nameUsed);
|
|
146
|
+
checker.addPackageNamespace(
|
|
147
|
+
nameUsed,
|
|
148
|
+
dep.exportedSymbols,
|
|
149
|
+
dep.exportedTypes,
|
|
120
150
|
);
|
|
121
|
-
|
|
151
|
+
checker.trackImport(nameUsed, { _line }, p._filename, p._source);
|
|
122
152
|
}
|
|
123
|
-
|
|
124
|
-
// Recursively compile dependency
|
|
125
|
-
const dep = compileDir(depDir);
|
|
126
|
-
preambles.push(dep.js);
|
|
127
|
-
bundledPackages.add(dep.pkgName);
|
|
128
|
-
checker.addPackageNamespace(
|
|
129
|
-
dep.pkgName,
|
|
130
|
-
dep.exportedSymbols,
|
|
131
|
-
dep.exportedTypes,
|
|
132
|
-
);
|
|
133
153
|
}
|
|
134
154
|
}
|
|
135
155
|
|
|
136
156
|
// ── 3. Type-check ─────────────────────────────────────────────
|
|
137
157
|
const errors = checker.checkAll(programs);
|
|
158
|
+
checker.reportUnusedImports();
|
|
138
159
|
if (errors.length > 0) {
|
|
139
160
|
const msgs = errors.map((e) => e.message).join("\n");
|
|
140
161
|
throw new Error(msgs);
|
package/src/dts-parser.js
CHANGED
|
@@ -404,13 +404,11 @@ export class DtsParser {
|
|
|
404
404
|
if (this.eof() || this.ch() === "}") return;
|
|
405
405
|
|
|
406
406
|
// Skip modifiers (export, declare, static, readonly, etc.)
|
|
407
|
-
let _exported = false;
|
|
408
407
|
while (true) {
|
|
409
408
|
this.skip();
|
|
410
409
|
let found = false;
|
|
411
410
|
for (const mod of SKIP_MODIFIERS) {
|
|
412
411
|
if (this.matchKw(mod)) {
|
|
413
|
-
if (mod === "export") _exported = true;
|
|
414
412
|
found = true;
|
|
415
413
|
break;
|
|
416
414
|
}
|
|
@@ -604,13 +602,11 @@ export class DtsParser {
|
|
|
604
602
|
if (this.eof() || this.ch() === "}") break;
|
|
605
603
|
|
|
606
604
|
// Collect modifiers
|
|
607
|
-
let _isExport = false;
|
|
608
605
|
while (true) {
|
|
609
606
|
this.skip();
|
|
610
607
|
let found = false;
|
|
611
608
|
for (const mod of SKIP_MODIFIERS) {
|
|
612
609
|
if (this.matchKw(mod)) {
|
|
613
|
-
if (mod === "export") _isExport = true;
|
|
614
610
|
found = true;
|
|
615
611
|
break;
|
|
616
612
|
}
|
package/src/index.js
CHANGED
|
@@ -148,16 +148,14 @@ function runCompile() {
|
|
|
148
148
|
throw new Error(`cannot read '${inputArg}': ${e.message}`);
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
|
|
152
|
-
tokens = new Lexer(source, basename(inputPath)).tokenize();
|
|
151
|
+
const tokens = new Lexer(source, basename(inputPath)).tokenize();
|
|
153
152
|
|
|
154
153
|
if (dumpTokens) {
|
|
155
154
|
for (const tok of tokens) console.log(tok.toString());
|
|
156
155
|
process.exit(0);
|
|
157
156
|
}
|
|
158
157
|
|
|
159
|
-
|
|
160
|
-
ast = new Parser(tokens, basename(inputPath), source).parse();
|
|
158
|
+
const ast = new Parser(tokens, basename(inputPath), source).parse();
|
|
161
159
|
ast._source = source;
|
|
162
160
|
|
|
163
161
|
if (dumpAst) {
|
|
@@ -170,7 +168,7 @@ function runCompile() {
|
|
|
170
168
|
const jsImports = new Map();
|
|
171
169
|
|
|
172
170
|
for (const imp of ast.imports) {
|
|
173
|
-
for (const path of imp.
|
|
171
|
+
for (const { path } of imp.imports) {
|
|
174
172
|
if (!path.startsWith("js:")) continue;
|
|
175
173
|
const dtsPath = join(fromDir, path.slice(3));
|
|
176
174
|
try {
|
|
@@ -193,7 +191,7 @@ function runCompile() {
|
|
|
193
191
|
const preambles = [];
|
|
194
192
|
|
|
195
193
|
for (const imp of ast.imports) {
|
|
196
|
-
for (const path of imp.
|
|
194
|
+
for (const { path, alias } of imp.imports) {
|
|
197
195
|
if (!isLocalPath(path)) continue;
|
|
198
196
|
const depDir = resolveGwDir(path, inputPath);
|
|
199
197
|
if (!depDir) {
|
|
@@ -204,9 +202,10 @@ function runCompile() {
|
|
|
204
202
|
}
|
|
205
203
|
const dep = compileDir(depDir);
|
|
206
204
|
preambles.push(dep.js);
|
|
207
|
-
|
|
205
|
+
const nameUsed = alias ?? dep.pkgName;
|
|
206
|
+
bundledPackages.add(nameUsed);
|
|
208
207
|
checker.addPackageNamespace(
|
|
209
|
-
|
|
208
|
+
nameUsed,
|
|
210
209
|
dep.exportedSymbols,
|
|
211
210
|
dep.exportedTypes,
|
|
212
211
|
);
|
|
@@ -228,15 +227,7 @@ function runCompile() {
|
|
|
228
227
|
}
|
|
229
228
|
|
|
230
229
|
const output = preambles.length > 0 ? `${preambles.join("\n")}\n${js}` : js;
|
|
231
|
-
return { js: output
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
function _writeOutput(js) {
|
|
235
|
-
if (outputFile) {
|
|
236
|
-
writeFileSync(outputFile, `${js}\n`);
|
|
237
|
-
} else {
|
|
238
|
-
console.log(js);
|
|
239
|
-
}
|
|
230
|
+
return { js: output };
|
|
240
231
|
}
|
|
241
232
|
|
|
242
233
|
// ── Minify helper ────────────────────────────────────────────
|
|
@@ -299,7 +290,7 @@ function timestamp() {
|
|
|
299
290
|
return new Date().toLocaleTimeString();
|
|
300
291
|
}
|
|
301
292
|
|
|
302
|
-
async function buildOnce(
|
|
293
|
+
async function buildOnce() {
|
|
303
294
|
try {
|
|
304
295
|
const startMs = performance.now();
|
|
305
296
|
const result = runCompile();
|
|
@@ -323,7 +314,7 @@ async function buildOnce(_label) {
|
|
|
323
314
|
}
|
|
324
315
|
|
|
325
316
|
// Initial build
|
|
326
|
-
buildOnce(
|
|
317
|
+
buildOnce();
|
|
327
318
|
|
|
328
319
|
// Determine what to watch
|
|
329
320
|
const watchTarget = isDir ? inputPath : dirname(inputPath);
|
|
@@ -332,7 +323,7 @@ let debounce = null;
|
|
|
332
323
|
watch(watchTarget, { recursive: true }, (_event, filename) => {
|
|
333
324
|
if (filename && !filename.endsWith(".go")) return;
|
|
334
325
|
clearTimeout(debounce);
|
|
335
|
-
debounce = setTimeout(() => buildOnce(
|
|
326
|
+
debounce = setTimeout(() => buildOnce(), 80);
|
|
336
327
|
});
|
|
337
328
|
|
|
338
329
|
console.error(`[${timestamp()}] gofront: watching ${inputArg} ...`);
|
package/src/lexer.js
CHANGED
|
@@ -35,6 +35,9 @@ export const T = {
|
|
|
35
35
|
DEFER: "defer",
|
|
36
36
|
ASYNC: "async",
|
|
37
37
|
AWAIT: "await",
|
|
38
|
+
GO: "go",
|
|
39
|
+
CHAN: "chan",
|
|
40
|
+
SELECT: "select",
|
|
38
41
|
|
|
39
42
|
// Operators
|
|
40
43
|
PLUS: "+",
|
|
@@ -58,11 +61,17 @@ export const T = {
|
|
|
58
61
|
STAR_ASSIGN: "*=",
|
|
59
62
|
SLASH_ASSIGN: "/=",
|
|
60
63
|
PERCENT_ASSIGN: "%=",
|
|
64
|
+
AMP_ASSIGN: "&=",
|
|
65
|
+
PIPE_ASSIGN: "|=",
|
|
66
|
+
CARET_ASSIGN: "^=",
|
|
67
|
+
LSHIFT_ASSIGN: "<<=",
|
|
68
|
+
RSHIFT_ASSIGN: ">>=",
|
|
61
69
|
INC: "++",
|
|
62
70
|
DEC: "--",
|
|
63
71
|
AMP: "&",
|
|
64
72
|
PIPE: "|",
|
|
65
73
|
CARET: "^",
|
|
74
|
+
AND_NOT: "&^",
|
|
66
75
|
LSHIFT: "<<",
|
|
67
76
|
RSHIFT: ">>",
|
|
68
77
|
ELLIPSIS: "...",
|
|
@@ -131,6 +140,9 @@ const KEYWORDS = new Set([
|
|
|
131
140
|
"defer",
|
|
132
141
|
"async",
|
|
133
142
|
"await",
|
|
143
|
+
"go",
|
|
144
|
+
"chan",
|
|
145
|
+
"select",
|
|
134
146
|
]);
|
|
135
147
|
|
|
136
148
|
export class Token {
|
|
@@ -212,16 +224,28 @@ export class Lexer {
|
|
|
212
224
|
while (this.pos < this.src.length && this.peek() !== "\n")
|
|
213
225
|
this.advance();
|
|
214
226
|
} else if (ch === "/" && this.peek(1) === "*") {
|
|
227
|
+
const startLine = this.line,
|
|
228
|
+
startCol = this.col;
|
|
215
229
|
this.advance();
|
|
216
230
|
this.advance();
|
|
231
|
+
let closed = false;
|
|
217
232
|
while (this.pos < this.src.length) {
|
|
218
233
|
if (this.peek() === "*" && this.peek(1) === "/") {
|
|
219
234
|
this.advance();
|
|
220
235
|
this.advance();
|
|
236
|
+
closed = true;
|
|
221
237
|
break;
|
|
222
238
|
}
|
|
223
239
|
this.advance();
|
|
224
240
|
}
|
|
241
|
+
if (!closed)
|
|
242
|
+
throw new LexError(
|
|
243
|
+
"Unterminated block comment",
|
|
244
|
+
startLine,
|
|
245
|
+
startCol,
|
|
246
|
+
this.filename,
|
|
247
|
+
this.src,
|
|
248
|
+
);
|
|
225
249
|
} else {
|
|
226
250
|
break;
|
|
227
251
|
}
|
|
@@ -267,7 +291,7 @@ export class Lexer {
|
|
|
267
291
|
}
|
|
268
292
|
}
|
|
269
293
|
if (this.pos >= this.src.length)
|
|
270
|
-
throw new LexError("Unterminated string", l, c, this.filename);
|
|
294
|
+
throw new LexError("Unterminated string", l, c, this.filename, this.src);
|
|
271
295
|
this.advance(); // closing "
|
|
272
296
|
return s;
|
|
273
297
|
}
|
|
@@ -281,23 +305,145 @@ export class Lexer {
|
|
|
281
305
|
return s;
|
|
282
306
|
}
|
|
283
307
|
|
|
308
|
+
readRuneLiteral() {
|
|
309
|
+
const l = this.line,
|
|
310
|
+
c = this.col;
|
|
311
|
+
this.advance(); // opening '
|
|
312
|
+
let code;
|
|
313
|
+
if (this.peek() === "\\") {
|
|
314
|
+
this.advance();
|
|
315
|
+
const esc = this.advance();
|
|
316
|
+
switch (esc) {
|
|
317
|
+
case "n":
|
|
318
|
+
code = 10;
|
|
319
|
+
break;
|
|
320
|
+
case "t":
|
|
321
|
+
code = 9;
|
|
322
|
+
break;
|
|
323
|
+
case "r":
|
|
324
|
+
code = 13;
|
|
325
|
+
break;
|
|
326
|
+
case "'":
|
|
327
|
+
code = 39;
|
|
328
|
+
break;
|
|
329
|
+
case "\\":
|
|
330
|
+
code = 92;
|
|
331
|
+
break;
|
|
332
|
+
case "0":
|
|
333
|
+
code = 0;
|
|
334
|
+
break;
|
|
335
|
+
default:
|
|
336
|
+
throw new LexError(
|
|
337
|
+
`Unknown escape in rune literal: \\${esc}`,
|
|
338
|
+
l,
|
|
339
|
+
c,
|
|
340
|
+
this.filename,
|
|
341
|
+
this.src,
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
} else if (this.peek() !== "'") {
|
|
345
|
+
code = this.src.codePointAt(this.pos);
|
|
346
|
+
this.advance();
|
|
347
|
+
} else {
|
|
348
|
+
throw new LexError("Empty rune literal", l, c, this.filename, this.src);
|
|
349
|
+
}
|
|
350
|
+
if (this.peek() !== "'")
|
|
351
|
+
throw new LexError(
|
|
352
|
+
"Rune literal must contain exactly one character",
|
|
353
|
+
l,
|
|
354
|
+
c,
|
|
355
|
+
this.filename,
|
|
356
|
+
this.src,
|
|
357
|
+
);
|
|
358
|
+
this.advance(); // closing '
|
|
359
|
+
return String(code);
|
|
360
|
+
}
|
|
361
|
+
|
|
284
362
|
readNumber() {
|
|
285
363
|
let n = "";
|
|
286
364
|
let isFloat = false;
|
|
287
|
-
|
|
288
|
-
|
|
365
|
+
|
|
366
|
+
// Check for prefix: 0b, 0o, 0x
|
|
367
|
+
const first = this.advance();
|
|
368
|
+
n += first;
|
|
369
|
+
if (first === "0") {
|
|
370
|
+
const p = this.peek();
|
|
371
|
+
if (p === "b" || p === "B") {
|
|
372
|
+
n += this.advance();
|
|
373
|
+
while (this.pos < this.src.length && /[01_]/.test(this.peek())) {
|
|
374
|
+
const ch = this.advance();
|
|
375
|
+
if (ch !== "_") n += ch;
|
|
376
|
+
}
|
|
377
|
+
return { n, isFloat: false };
|
|
378
|
+
}
|
|
379
|
+
if (p === "o" || p === "O") {
|
|
380
|
+
n += this.advance();
|
|
381
|
+
while (this.pos < this.src.length && /[0-7_]/.test(this.peek())) {
|
|
382
|
+
const ch = this.advance();
|
|
383
|
+
if (ch !== "_") n += ch;
|
|
384
|
+
}
|
|
385
|
+
return { n, isFloat: false };
|
|
386
|
+
}
|
|
387
|
+
if (p === "x" || p === "X") {
|
|
388
|
+
n += this.advance();
|
|
389
|
+
while (this.pos < this.src.length && /[0-9a-fA-F_]/.test(this.peek())) {
|
|
390
|
+
const ch = this.advance();
|
|
391
|
+
if (ch !== "_") n += ch;
|
|
392
|
+
}
|
|
393
|
+
// Hex float: 0x1.Fp10 or 0xAp-2
|
|
394
|
+
if (this.peek() === "." || this.peek() === "p" || this.peek() === "P") {
|
|
395
|
+
let frac = "";
|
|
396
|
+
if (this.peek() === ".") {
|
|
397
|
+
this.advance(); // skip the dot (don't add to n)
|
|
398
|
+
while (
|
|
399
|
+
this.pos < this.src.length &&
|
|
400
|
+
/[0-9a-fA-F_]/.test(this.peek())
|
|
401
|
+
) {
|
|
402
|
+
const ch = this.advance();
|
|
403
|
+
if (ch !== "_") frac += ch;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
if (this.peek() === "p" || this.peek() === "P") {
|
|
407
|
+
this.advance(); // skip p/P
|
|
408
|
+
let exp = "";
|
|
409
|
+
if (this.peek() === "+" || this.peek() === "-")
|
|
410
|
+
exp += this.advance();
|
|
411
|
+
while (this.pos < this.src.length && /[0-9]/.test(this.peek()))
|
|
412
|
+
exp += this.advance();
|
|
413
|
+
// Evaluate: JS can't parse hex floats, so convert manually
|
|
414
|
+
// n is "0x1" (integer hex part), frac is hex fractional digits
|
|
415
|
+
let mantissa = Number(n);
|
|
416
|
+
if (frac) {
|
|
417
|
+
mantissa += Number.parseInt(frac, 16) / 16 ** frac.length;
|
|
418
|
+
}
|
|
419
|
+
const value = mantissa * 2 ** Number(exp);
|
|
420
|
+
return { n: String(value), isFloat: true };
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
return { n, isFloat: false };
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
while (this.pos < this.src.length && /[0-9_]/.test(this.peek())) {
|
|
428
|
+
const ch = this.advance();
|
|
429
|
+
if (ch !== "_") n += ch;
|
|
430
|
+
}
|
|
289
431
|
if (this.peek() === "." && /[0-9]/.test(this.peek(1))) {
|
|
290
432
|
isFloat = true;
|
|
291
433
|
n += this.advance();
|
|
292
|
-
while (this.pos < this.src.length && /[0-
|
|
293
|
-
|
|
434
|
+
while (this.pos < this.src.length && /[0-9_]/.test(this.peek())) {
|
|
435
|
+
const ch = this.advance();
|
|
436
|
+
if (ch !== "_") n += ch;
|
|
437
|
+
}
|
|
294
438
|
}
|
|
295
439
|
if (this.peek() === "e" || this.peek() === "E") {
|
|
296
440
|
isFloat = true;
|
|
297
441
|
n += this.advance();
|
|
298
442
|
if (this.peek() === "+" || this.peek() === "-") n += this.advance();
|
|
299
|
-
while (this.pos < this.src.length && /[0-
|
|
300
|
-
|
|
443
|
+
while (this.pos < this.src.length && /[0-9_]/.test(this.peek())) {
|
|
444
|
+
const ch = this.advance();
|
|
445
|
+
if (ch !== "_") n += ch;
|
|
446
|
+
}
|
|
301
447
|
}
|
|
302
448
|
return { n, isFloat };
|
|
303
449
|
}
|
|
@@ -347,6 +493,10 @@ export class Lexer {
|
|
|
347
493
|
this.push(T.STRING, this.readRawString(), l, c);
|
|
348
494
|
continue;
|
|
349
495
|
}
|
|
496
|
+
if (ch === "'") {
|
|
497
|
+
this.push(T.INT, this.readRuneLiteral(), l, c);
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
350
500
|
|
|
351
501
|
// Numbers
|
|
352
502
|
if (/[0-9]/.test(ch)) {
|
|
@@ -396,25 +546,33 @@ export class Lexer {
|
|
|
396
546
|
else this.push(T.NOT, "!", l, c);
|
|
397
547
|
break;
|
|
398
548
|
case "<":
|
|
399
|
-
if (this.match("<"))
|
|
400
|
-
|
|
549
|
+
if (this.match("<")) {
|
|
550
|
+
if (this.match("=")) this.push(T.LSHIFT_ASSIGN, "<<=", l, c);
|
|
551
|
+
else this.push(T.LSHIFT, "<<", l, c);
|
|
552
|
+
} else if (this.match("=")) this.push(T.LTE, "<=", l, c);
|
|
401
553
|
else this.push(T.LT, "<", l, c);
|
|
402
554
|
break;
|
|
403
555
|
case ">":
|
|
404
|
-
if (this.match(">"))
|
|
405
|
-
|
|
556
|
+
if (this.match(">")) {
|
|
557
|
+
if (this.match("=")) this.push(T.RSHIFT_ASSIGN, ">>=", l, c);
|
|
558
|
+
else this.push(T.RSHIFT, ">>", l, c);
|
|
559
|
+
} else if (this.match("=")) this.push(T.GTE, ">=", l, c);
|
|
406
560
|
else this.push(T.GT, ">", l, c);
|
|
407
561
|
break;
|
|
408
562
|
case "&":
|
|
409
563
|
if (this.match("&")) this.push(T.AND, "&&", l, c);
|
|
564
|
+
else if (this.match("^")) this.push(T.AND_NOT, "&^", l, c);
|
|
565
|
+
else if (this.match("=")) this.push(T.AMP_ASSIGN, "&=", l, c);
|
|
410
566
|
else this.push(T.AMP, "&", l, c);
|
|
411
567
|
break;
|
|
412
568
|
case "|":
|
|
413
569
|
if (this.match("|")) this.push(T.OR, "||", l, c);
|
|
570
|
+
else if (this.match("=")) this.push(T.PIPE_ASSIGN, "|=", l, c);
|
|
414
571
|
else this.push(T.PIPE, "|", l, c);
|
|
415
572
|
break;
|
|
416
573
|
case "^":
|
|
417
|
-
this.push(T.
|
|
574
|
+
if (this.match("=")) this.push(T.CARET_ASSIGN, "^=", l, c);
|
|
575
|
+
else this.push(T.CARET, "^", l, c);
|
|
418
576
|
break;
|
|
419
577
|
case ":":
|
|
420
578
|
if (this.match("=")) this.push(T.DEFINE, ":=", l, c);
|