shell-dsl 0.0.6 → 0.0.8
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 +3 -1
- package/dist/cjs/index.cjs +14 -4
- package/dist/cjs/index.cjs.map +3 -3
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/src/commands/awk/awk.cjs +276 -0
- package/dist/cjs/src/commands/awk/awk.cjs.map +10 -0
- package/dist/cjs/src/commands/break-continue/break-continue.cjs +56 -0
- package/dist/cjs/src/commands/break-continue/break-continue.cjs.map +10 -0
- package/dist/cjs/src/commands/cat/cat.cjs +57 -0
- package/dist/cjs/src/commands/cat/cat.cjs.map +10 -0
- package/dist/cjs/src/commands/cp/cp.cjs +126 -0
- package/dist/cjs/src/commands/cp/cp.cjs.map +10 -0
- package/dist/cjs/src/commands/echo/echo.cjs +50 -0
- package/dist/cjs/src/commands/echo/echo.cjs.map +10 -0
- package/dist/cjs/src/commands/find/find.cjs +251 -0
- package/dist/cjs/src/commands/find/find.cjs.map +10 -0
- package/dist/cjs/src/commands/grep/grep.cjs +510 -0
- package/dist/cjs/src/commands/grep/grep.cjs.map +10 -0
- package/dist/cjs/src/commands/head/head.cjs +95 -0
- package/dist/cjs/src/commands/head/head.cjs.map +10 -0
- package/dist/cjs/src/commands/index.cjs +136 -0
- package/dist/cjs/src/commands/index.cjs.map +10 -0
- package/dist/cjs/src/commands/ls/ls.cjs +119 -0
- package/dist/cjs/src/commands/ls/ls.cjs.map +10 -0
- package/dist/cjs/src/commands/mkdir/mkdir.cjs +64 -0
- package/dist/cjs/src/commands/mkdir/mkdir.cjs.map +10 -0
- package/dist/cjs/src/commands/mv/mv.cjs +118 -0
- package/dist/cjs/src/commands/mv/mv.cjs.map +10 -0
- package/dist/cjs/src/commands/pwd/pwd.cjs +41 -0
- package/dist/cjs/src/commands/pwd/pwd.cjs.map +10 -0
- package/dist/cjs/src/commands/rm/rm.cjs +82 -0
- package/dist/cjs/src/commands/rm/rm.cjs.map +10 -0
- package/dist/cjs/src/commands/sed/sed.cjs +218 -0
- package/dist/cjs/src/commands/sed/sed.cjs.map +10 -0
- package/dist/cjs/src/commands/sort/sort.cjs +105 -0
- package/dist/cjs/src/commands/sort/sort.cjs.map +10 -0
- package/dist/cjs/src/commands/tail/tail.cjs +95 -0
- package/dist/cjs/src/commands/tail/tail.cjs.map +10 -0
- package/dist/cjs/src/commands/tee/tee.cjs +65 -0
- package/dist/cjs/src/commands/tee/tee.cjs.map +10 -0
- package/dist/cjs/src/commands/test/test.cjs +148 -0
- package/dist/cjs/src/commands/test/test.cjs.map +10 -0
- package/dist/cjs/src/commands/touch/touch.cjs +70 -0
- package/dist/cjs/src/commands/touch/touch.cjs.map +10 -0
- package/dist/cjs/src/commands/tree/tree.cjs +161 -0
- package/dist/cjs/src/commands/tree/tree.cjs.map +10 -0
- package/dist/cjs/src/commands/true-false/true-false.cjs +43 -0
- package/dist/cjs/src/commands/true-false/true-false.cjs.map +10 -0
- package/dist/cjs/src/commands/uniq/uniq.cjs +116 -0
- package/dist/cjs/src/commands/uniq/uniq.cjs.map +10 -0
- package/dist/cjs/src/commands/wc/wc.cjs +116 -0
- package/dist/cjs/src/commands/wc/wc.cjs.map +10 -0
- package/dist/cjs/src/index.cjs +10 -2
- package/dist/cjs/src/index.cjs.map +3 -3
- package/dist/cjs/src/interpreter/index.cjs +4 -2
- package/dist/cjs/src/interpreter/index.cjs.map +3 -3
- package/dist/cjs/src/interpreter/interpreter.cjs +390 -2
- package/dist/cjs/src/interpreter/interpreter.cjs.map +3 -3
- package/dist/cjs/src/lexer/index.cjs +3 -2
- package/dist/cjs/src/lexer/index.cjs.map +3 -3
- package/dist/cjs/src/lexer/lexer.cjs +359 -8
- package/dist/cjs/src/lexer/lexer.cjs.map +3 -3
- package/dist/cjs/src/lexer/tokens.cjs +35 -2
- package/dist/cjs/src/lexer/tokens.cjs.map +3 -3
- package/dist/cjs/src/parser/ast.cjs +25 -1
- package/dist/cjs/src/parser/ast.cjs.map +3 -3
- package/dist/cjs/src/parser/index.cjs +7 -1
- package/dist/cjs/src/parser/index.cjs.map +3 -3
- package/dist/cjs/src/parser/parser.cjs +280 -8
- package/dist/cjs/src/parser/parser.cjs.map +3 -3
- package/dist/cjs/src/shell-dsl.cjs +2 -2
- package/dist/cjs/src/shell-dsl.cjs.map +3 -3
- package/dist/mjs/index.mjs +25 -5
- package/dist/mjs/index.mjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/src/commands/awk/awk.mjs +246 -0
- package/dist/mjs/src/commands/awk/awk.mjs.map +10 -0
- package/dist/mjs/src/commands/break-continue/break-continue.mjs +26 -0
- package/dist/mjs/src/commands/break-continue/break-continue.mjs.map +10 -0
- package/dist/mjs/src/commands/cat/cat.mjs +27 -0
- package/dist/mjs/src/commands/cat/cat.mjs.map +10 -0
- package/dist/mjs/src/commands/cp/cp.mjs +96 -0
- package/dist/mjs/src/commands/cp/cp.mjs.map +10 -0
- package/dist/mjs/src/commands/echo/echo.mjs +20 -0
- package/dist/mjs/src/commands/echo/echo.mjs.map +10 -0
- package/dist/mjs/src/commands/find/find.mjs +221 -0
- package/dist/mjs/src/commands/find/find.mjs.map +10 -0
- package/dist/mjs/src/commands/grep/grep.mjs +480 -0
- package/dist/mjs/src/commands/grep/grep.mjs.map +10 -0
- package/dist/mjs/src/commands/head/head.mjs +65 -0
- package/dist/mjs/src/commands/head/head.mjs.map +10 -0
- package/dist/mjs/src/commands/index.mjs +106 -0
- package/dist/mjs/src/commands/index.mjs.map +10 -0
- package/dist/mjs/src/commands/ls/ls.mjs +89 -0
- package/dist/mjs/src/commands/ls/ls.mjs.map +10 -0
- package/dist/mjs/src/commands/mkdir/mkdir.mjs +34 -0
- package/dist/mjs/src/commands/mkdir/mkdir.mjs.map +10 -0
- package/dist/mjs/src/commands/mv/mv.mjs +88 -0
- package/dist/mjs/src/commands/mv/mv.mjs.map +10 -0
- package/dist/mjs/src/commands/pwd/pwd.mjs +11 -0
- package/dist/mjs/src/commands/pwd/pwd.mjs.map +10 -0
- package/dist/mjs/src/commands/rm/rm.mjs +52 -0
- package/dist/mjs/src/commands/rm/rm.mjs.map +10 -0
- package/dist/mjs/src/commands/sed/sed.mjs +188 -0
- package/dist/mjs/src/commands/sed/sed.mjs.map +10 -0
- package/dist/mjs/src/commands/sort/sort.mjs +75 -0
- package/dist/mjs/src/commands/sort/sort.mjs.map +10 -0
- package/dist/mjs/src/commands/tail/tail.mjs +65 -0
- package/dist/mjs/src/commands/tail/tail.mjs.map +10 -0
- package/dist/mjs/src/commands/tee/tee.mjs +35 -0
- package/dist/mjs/src/commands/tee/tee.mjs.map +10 -0
- package/dist/mjs/src/commands/test/test.mjs +118 -0
- package/dist/mjs/src/commands/test/test.mjs.map +10 -0
- package/dist/mjs/src/commands/touch/touch.mjs +40 -0
- package/dist/mjs/src/commands/touch/touch.mjs.map +10 -0
- package/dist/mjs/src/commands/tree/tree.mjs +131 -0
- package/dist/mjs/src/commands/tree/tree.mjs.map +10 -0
- package/dist/mjs/src/commands/true-false/true-false.mjs +13 -0
- package/dist/mjs/src/commands/true-false/true-false.mjs.map +10 -0
- package/dist/mjs/src/commands/uniq/uniq.mjs +86 -0
- package/dist/mjs/src/commands/uniq/uniq.mjs.map +10 -0
- package/dist/mjs/src/commands/wc/wc.mjs +86 -0
- package/dist/mjs/src/commands/wc/wc.mjs.map +10 -0
- package/dist/mjs/src/index.mjs +18 -4
- package/dist/mjs/src/index.mjs.map +3 -3
- package/dist/mjs/src/interpreter/index.mjs +5 -3
- package/dist/mjs/src/interpreter/index.mjs.map +2 -2
- package/dist/mjs/src/interpreter/interpreter.mjs +390 -2
- package/dist/mjs/src/interpreter/interpreter.mjs.map +3 -3
- package/dist/mjs/src/lexer/index.mjs +4 -3
- package/dist/mjs/src/lexer/index.mjs.map +2 -2
- package/dist/mjs/src/lexer/lexer.mjs +359 -8
- package/dist/mjs/src/lexer/lexer.mjs.map +3 -3
- package/dist/mjs/src/lexer/tokens.mjs +35 -2
- package/dist/mjs/src/lexer/tokens.mjs.map +3 -3
- package/dist/mjs/src/parser/ast.mjs +25 -1
- package/dist/mjs/src/parser/ast.mjs.map +3 -3
- package/dist/mjs/src/parser/index.mjs +14 -2
- package/dist/mjs/src/parser/index.mjs.map +3 -3
- package/dist/mjs/src/parser/parser.mjs +280 -8
- package/dist/mjs/src/parser/parser.mjs.map +3 -3
- package/dist/mjs/src/shell-dsl.mjs +2 -2
- package/dist/mjs/src/shell-dsl.mjs.map +3 -3
- package/dist/types/index.d.ts +2 -2
- package/dist/types/src/commands/awk/awk.d.ts +2 -0
- package/dist/types/src/commands/break-continue/break-continue.d.ts +3 -0
- package/dist/types/src/commands/cat/cat.d.ts +2 -0
- package/dist/types/src/commands/cp/cp.d.ts +2 -0
- package/dist/types/src/commands/echo/echo.d.ts +2 -0
- package/dist/types/src/commands/find/find.d.ts +2 -0
- package/dist/types/src/commands/grep/grep.d.ts +2 -0
- package/dist/types/src/commands/head/head.d.ts +2 -0
- package/dist/types/src/commands/index.d.ts +25 -0
- package/dist/types/src/commands/ls/ls.d.ts +2 -0
- package/dist/types/src/commands/mkdir/mkdir.d.ts +2 -0
- package/dist/types/src/commands/mv/mv.d.ts +2 -0
- package/dist/types/src/commands/pwd/pwd.d.ts +2 -0
- package/dist/types/src/commands/rm/rm.d.ts +2 -0
- package/dist/types/src/commands/sed/sed.d.ts +2 -0
- package/dist/types/src/commands/sort/sort.d.ts +2 -0
- package/dist/types/src/commands/tail/tail.d.ts +2 -0
- package/dist/types/src/commands/tee/tee.d.ts +2 -0
- package/dist/types/{commands → src/commands/test}/test.d.ts +1 -1
- package/dist/types/src/commands/touch/touch.d.ts +2 -0
- package/dist/types/src/commands/tree/tree.d.ts +2 -0
- package/dist/types/{commands → src/commands/true-false}/true-false.d.ts +1 -1
- package/dist/types/src/commands/uniq/uniq.d.ts +2 -0
- package/dist/types/src/commands/wc/wc.d.ts +2 -0
- package/dist/types/src/index.d.ts +3 -3
- package/dist/types/src/interpreter/index.d.ts +1 -1
- package/dist/types/src/interpreter/interpreter.d.ts +18 -0
- package/dist/types/src/lexer/index.d.ts +2 -2
- package/dist/types/src/lexer/lexer.d.ts +16 -2
- package/dist/types/src/lexer/tokens.d.ts +20 -0
- package/dist/types/src/parser/ast.d.ts +47 -1
- package/dist/types/src/parser/index.d.ts +2 -2
- package/dist/types/src/parser/parser.d.ts +15 -0
- package/package.json +1 -1
- package/dist/types/commands/cat.d.ts +0 -2
- package/dist/types/commands/cp.d.ts +0 -2
- package/dist/types/commands/echo.d.ts +0 -2
- package/dist/types/commands/find.d.ts +0 -2
- package/dist/types/commands/grep.d.ts +0 -2
- package/dist/types/commands/head.d.ts +0 -2
- package/dist/types/commands/index.d.ts +0 -22
- package/dist/types/commands/ls.d.ts +0 -2
- package/dist/types/commands/mkdir.d.ts +0 -2
- package/dist/types/commands/mv.d.ts +0 -2
- package/dist/types/commands/pwd.d.ts +0 -2
- package/dist/types/commands/rm.d.ts +0 -2
- package/dist/types/commands/sort.d.ts +0 -2
- package/dist/types/commands/tail.d.ts +0 -2
- package/dist/types/commands/tee.d.ts +0 -2
- package/dist/types/commands/touch.d.ts +0 -2
- package/dist/types/commands/tree.d.ts +0 -2
- package/dist/types/commands/uniq.d.ts +0 -2
- package/dist/types/commands/wc.d.ts +0 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/lexer/lexer.ts
|
|
2
2
|
import { LexError } from "../errors.mjs";
|
|
3
|
+
import { KEYWORDS } from "./tokens.mjs";
|
|
3
4
|
var GLOB_CHARS = new Set(["*", "?", "[", "{", "}"]);
|
|
4
5
|
var WORD_BREAK_CHARS = new Set([
|
|
5
6
|
" ",
|
|
@@ -25,13 +26,20 @@ class Lexer {
|
|
|
25
26
|
pos = 0;
|
|
26
27
|
line = 1;
|
|
27
28
|
column = 1;
|
|
28
|
-
|
|
29
|
+
tokenQueue = [];
|
|
30
|
+
preserveNewlines;
|
|
31
|
+
constructor(source, options) {
|
|
29
32
|
this.source = source;
|
|
33
|
+
this.preserveNewlines = options?.preserveNewlines ?? false;
|
|
30
34
|
}
|
|
31
35
|
tokenize() {
|
|
32
36
|
const tokens = [];
|
|
33
|
-
while (!this.isAtEnd()) {
|
|
34
|
-
this.
|
|
37
|
+
while (!this.isAtEnd() || this.tokenQueue.length > 0) {
|
|
38
|
+
if (this.tokenQueue.length > 0) {
|
|
39
|
+
tokens.push(this.tokenQueue.shift());
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
this.skipWhitespaceExceptNewlines();
|
|
35
43
|
if (this.isAtEnd())
|
|
36
44
|
break;
|
|
37
45
|
const token = this.nextToken();
|
|
@@ -43,11 +51,34 @@ class Lexer {
|
|
|
43
51
|
return tokens;
|
|
44
52
|
}
|
|
45
53
|
nextToken() {
|
|
54
|
+
if (this.tokenQueue.length > 0) {
|
|
55
|
+
return this.tokenQueue.shift();
|
|
56
|
+
}
|
|
46
57
|
const char = this.peek();
|
|
58
|
+
if (char === `
|
|
59
|
+
`) {
|
|
60
|
+
this.advance();
|
|
61
|
+
while (this.peek() === `
|
|
62
|
+
`) {
|
|
63
|
+
this.advance();
|
|
64
|
+
}
|
|
65
|
+
if (this.preserveNewlines) {
|
|
66
|
+
return { type: "newline" };
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
47
70
|
if (char === "#") {
|
|
48
71
|
this.skipComment();
|
|
49
72
|
return null;
|
|
50
73
|
}
|
|
74
|
+
if (char === "(") {
|
|
75
|
+
this.advance();
|
|
76
|
+
return { type: "openParen" };
|
|
77
|
+
}
|
|
78
|
+
if (char === ")") {
|
|
79
|
+
this.advance();
|
|
80
|
+
return { type: "closeParen" };
|
|
81
|
+
}
|
|
51
82
|
if (char === "|") {
|
|
52
83
|
this.advance();
|
|
53
84
|
if (this.peek() === "|") {
|
|
@@ -74,6 +105,10 @@ class Lexer {
|
|
|
74
105
|
}
|
|
75
106
|
if (char === ";") {
|
|
76
107
|
this.advance();
|
|
108
|
+
if (this.peek() === ";") {
|
|
109
|
+
this.advance();
|
|
110
|
+
return { type: "doubleSemicolon" };
|
|
111
|
+
}
|
|
77
112
|
return { type: "semicolon" };
|
|
78
113
|
}
|
|
79
114
|
if (char === ">") {
|
|
@@ -86,6 +121,10 @@ class Lexer {
|
|
|
86
121
|
}
|
|
87
122
|
if (char === "<") {
|
|
88
123
|
this.advance();
|
|
124
|
+
if (this.peek() === "<") {
|
|
125
|
+
this.advance();
|
|
126
|
+
return this.readHeredoc();
|
|
127
|
+
}
|
|
89
128
|
return { type: "redirect", mode: "<" };
|
|
90
129
|
}
|
|
91
130
|
if (char === "1" || char === "2") {
|
|
@@ -134,6 +173,11 @@ class Lexer {
|
|
|
134
173
|
this.advance();
|
|
135
174
|
if (this.peek() === "(") {
|
|
136
175
|
this.advance();
|
|
176
|
+
if (this.peek() === "(") {
|
|
177
|
+
this.advance();
|
|
178
|
+
const expression = this.readUntilDoubleCloseParen();
|
|
179
|
+
return { type: "arithmetic", expression };
|
|
180
|
+
}
|
|
137
181
|
const command = this.readUntilMatchingParen();
|
|
138
182
|
return { type: "substitution", command };
|
|
139
183
|
}
|
|
@@ -157,6 +201,30 @@ class Lexer {
|
|
|
157
201
|
}
|
|
158
202
|
return { type: "variable", name };
|
|
159
203
|
}
|
|
204
|
+
readUntilDoubleCloseParen() {
|
|
205
|
+
let depth = 1;
|
|
206
|
+
let result = "";
|
|
207
|
+
while (!this.isAtEnd() && depth > 0) {
|
|
208
|
+
const char = this.peek();
|
|
209
|
+
if (char === "(" && this.peekAhead(1) === "(") {
|
|
210
|
+
depth++;
|
|
211
|
+
result += this.advance();
|
|
212
|
+
result += this.advance();
|
|
213
|
+
} else if (char === ")" && this.peekAhead(1) === ")") {
|
|
214
|
+
depth--;
|
|
215
|
+
if (depth === 0) {
|
|
216
|
+
this.advance();
|
|
217
|
+
this.advance();
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
result += this.advance();
|
|
221
|
+
result += this.advance();
|
|
222
|
+
} else {
|
|
223
|
+
result += this.advance();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return result;
|
|
227
|
+
}
|
|
160
228
|
readUntilMatchingParen() {
|
|
161
229
|
let depth = 1;
|
|
162
230
|
let result = "";
|
|
@@ -242,19 +310,297 @@ class Lexer {
|
|
|
242
310
|
value += this.advance();
|
|
243
311
|
}
|
|
244
312
|
}
|
|
313
|
+
const assignmentPrefixMatch = value.match(/^([a-zA-Z_][a-zA-Z0-9_]*)=$/);
|
|
314
|
+
if (assignmentPrefixMatch && (this.peek() === "$" || this.peek() === "'" || this.peek() === '"')) {
|
|
315
|
+
const name = assignmentPrefixMatch[1];
|
|
316
|
+
const valueTokens = this.readAssignmentValueTokens();
|
|
317
|
+
return {
|
|
318
|
+
type: "assignment",
|
|
319
|
+
name,
|
|
320
|
+
value: valueTokens.length === 1 && valueTokens[0].type === "word" ? valueTokens[0].value : valueTokens
|
|
321
|
+
};
|
|
322
|
+
}
|
|
245
323
|
const assignmentMatch = value.match(/^([a-zA-Z_][a-zA-Z0-9_]*)=(.*)$/);
|
|
246
324
|
if (assignmentMatch) {
|
|
325
|
+
const name = assignmentMatch[1];
|
|
326
|
+
const rawValue = assignmentMatch[2];
|
|
327
|
+
const parsedValue = this.parseAssignmentValue(rawValue);
|
|
247
328
|
return {
|
|
248
329
|
type: "assignment",
|
|
249
|
-
name
|
|
250
|
-
value:
|
|
330
|
+
name,
|
|
331
|
+
value: parsedValue
|
|
251
332
|
};
|
|
252
333
|
}
|
|
334
|
+
if (KEYWORDS.has(value)) {
|
|
335
|
+
return { type: "keyword", value };
|
|
336
|
+
}
|
|
253
337
|
if (hasGlobChars) {
|
|
254
338
|
return { type: "glob", pattern: value };
|
|
255
339
|
}
|
|
256
340
|
return { type: "word", value };
|
|
257
341
|
}
|
|
342
|
+
readAssignmentValueTokens() {
|
|
343
|
+
const tokens = [];
|
|
344
|
+
while (!this.isAtEnd()) {
|
|
345
|
+
const char = this.peek();
|
|
346
|
+
if (char === " " || char === "\t" || char === `
|
|
347
|
+
` || char === "\r" || char === ";" || char === "|" || char === "&" || char === ">" || char === "<") {
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
if (char === "$") {
|
|
351
|
+
tokens.push(this.readVariable());
|
|
352
|
+
} else if (char === "'") {
|
|
353
|
+
tokens.push(this.readSingleQuote());
|
|
354
|
+
} else if (char === '"') {
|
|
355
|
+
tokens.push(this.readDoubleQuote());
|
|
356
|
+
} else {
|
|
357
|
+
let word = "";
|
|
358
|
+
while (!this.isAtEnd() && !this.isWordBreak(this.peek())) {
|
|
359
|
+
word += this.advance();
|
|
360
|
+
}
|
|
361
|
+
if (word) {
|
|
362
|
+
tokens.push({ type: "word", value: word });
|
|
363
|
+
} else {
|
|
364
|
+
break;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return tokens;
|
|
369
|
+
}
|
|
370
|
+
parseAssignmentValue(value) {
|
|
371
|
+
if (!value.includes("$")) {
|
|
372
|
+
return value;
|
|
373
|
+
}
|
|
374
|
+
const tokens = [];
|
|
375
|
+
let i = 0;
|
|
376
|
+
let currentString = "";
|
|
377
|
+
while (i < value.length) {
|
|
378
|
+
if (value[i] === "$") {
|
|
379
|
+
if (currentString) {
|
|
380
|
+
tokens.push({ type: "word", value: currentString });
|
|
381
|
+
currentString = "";
|
|
382
|
+
}
|
|
383
|
+
i++;
|
|
384
|
+
if (i >= value.length) {
|
|
385
|
+
tokens.push({ type: "word", value: "$" });
|
|
386
|
+
break;
|
|
387
|
+
}
|
|
388
|
+
if (value[i] === "(" && value[i + 1] === "(") {
|
|
389
|
+
i += 2;
|
|
390
|
+
let depth = 1;
|
|
391
|
+
let expr = "";
|
|
392
|
+
while (i < value.length && depth > 0) {
|
|
393
|
+
if (value[i] === "(" && value[i + 1] === "(") {
|
|
394
|
+
depth++;
|
|
395
|
+
expr += value[i] + value[i + 1];
|
|
396
|
+
i += 2;
|
|
397
|
+
} else if (value[i] === ")" && value[i + 1] === ")") {
|
|
398
|
+
depth--;
|
|
399
|
+
if (depth > 0) {
|
|
400
|
+
expr += value[i] + value[i + 1];
|
|
401
|
+
i += 2;
|
|
402
|
+
} else {
|
|
403
|
+
i += 2;
|
|
404
|
+
}
|
|
405
|
+
} else {
|
|
406
|
+
expr += value[i];
|
|
407
|
+
i++;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
tokens.push({ type: "arithmetic", expression: expr });
|
|
411
|
+
} else if (value[i] === "{") {
|
|
412
|
+
i++;
|
|
413
|
+
let varName = "";
|
|
414
|
+
while (i < value.length && value[i] !== "}") {
|
|
415
|
+
varName += value[i];
|
|
416
|
+
i++;
|
|
417
|
+
}
|
|
418
|
+
if (i < value.length && value[i] === "}") {
|
|
419
|
+
i++;
|
|
420
|
+
}
|
|
421
|
+
tokens.push({ type: "variable", name: varName });
|
|
422
|
+
} else if (/[a-zA-Z_]/.test(value[i])) {
|
|
423
|
+
let varName = "";
|
|
424
|
+
while (i < value.length && /[a-zA-Z0-9_]/.test(value[i])) {
|
|
425
|
+
varName += value[i];
|
|
426
|
+
i++;
|
|
427
|
+
}
|
|
428
|
+
tokens.push({ type: "variable", name: varName });
|
|
429
|
+
} else if (value[i] === "(") {
|
|
430
|
+
i++;
|
|
431
|
+
let depth = 1;
|
|
432
|
+
let cmd = "";
|
|
433
|
+
while (i < value.length && depth > 0) {
|
|
434
|
+
if (value[i] === "(")
|
|
435
|
+
depth++;
|
|
436
|
+
else if (value[i] === ")")
|
|
437
|
+
depth--;
|
|
438
|
+
if (depth > 0) {
|
|
439
|
+
cmd += value[i];
|
|
440
|
+
}
|
|
441
|
+
i++;
|
|
442
|
+
}
|
|
443
|
+
tokens.push({ type: "substitution", command: cmd });
|
|
444
|
+
} else {
|
|
445
|
+
currentString += "$";
|
|
446
|
+
}
|
|
447
|
+
} else {
|
|
448
|
+
currentString += value[i];
|
|
449
|
+
i++;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
if (currentString) {
|
|
453
|
+
tokens.push({ type: "word", value: currentString });
|
|
454
|
+
}
|
|
455
|
+
if (tokens.length === 1 && tokens[0].type === "word") {
|
|
456
|
+
return tokens[0].value;
|
|
457
|
+
}
|
|
458
|
+
return tokens.length > 0 ? tokens : value;
|
|
459
|
+
}
|
|
460
|
+
readHeredoc() {
|
|
461
|
+
const stripTabs = this.peek() === "-";
|
|
462
|
+
if (stripTabs) {
|
|
463
|
+
this.advance();
|
|
464
|
+
}
|
|
465
|
+
while (this.peek() === " " || this.peek() === "\t") {
|
|
466
|
+
this.advance();
|
|
467
|
+
}
|
|
468
|
+
const { delimiter, expand } = this.readHeredocDelimiter();
|
|
469
|
+
this.tokenizeRestOfLine();
|
|
470
|
+
if (this.peek() === `
|
|
471
|
+
`) {
|
|
472
|
+
this.advance();
|
|
473
|
+
}
|
|
474
|
+
let content = "";
|
|
475
|
+
while (!this.isAtEnd()) {
|
|
476
|
+
const lineStart = this.pos;
|
|
477
|
+
let line = "";
|
|
478
|
+
while (!this.isAtEnd() && this.peek() !== `
|
|
479
|
+
`) {
|
|
480
|
+
line += this.advance();
|
|
481
|
+
}
|
|
482
|
+
const strippedLine = stripTabs ? line.replace(/^\t+/, "") : line;
|
|
483
|
+
if (strippedLine === delimiter) {
|
|
484
|
+
if (this.peek() === `
|
|
485
|
+
`) {
|
|
486
|
+
this.advance();
|
|
487
|
+
}
|
|
488
|
+
break;
|
|
489
|
+
}
|
|
490
|
+
if (stripTabs) {
|
|
491
|
+
content += line.replace(/^\t+/, "");
|
|
492
|
+
} else {
|
|
493
|
+
content += line;
|
|
494
|
+
}
|
|
495
|
+
if (this.peek() === `
|
|
496
|
+
`) {
|
|
497
|
+
content += this.advance();
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
return { type: "heredoc", content, expand };
|
|
501
|
+
}
|
|
502
|
+
readHeredocDelimiter() {
|
|
503
|
+
const quoteChar = this.peek();
|
|
504
|
+
if (quoteChar === "'" || quoteChar === '"') {
|
|
505
|
+
this.advance();
|
|
506
|
+
let delimiter2 = "";
|
|
507
|
+
while (!this.isAtEnd() && this.peek() !== quoteChar && this.peek() !== `
|
|
508
|
+
`) {
|
|
509
|
+
delimiter2 += this.advance();
|
|
510
|
+
}
|
|
511
|
+
if (this.peek() === quoteChar) {
|
|
512
|
+
this.advance();
|
|
513
|
+
}
|
|
514
|
+
return { delimiter: delimiter2, expand: false };
|
|
515
|
+
}
|
|
516
|
+
let delimiter = "";
|
|
517
|
+
while (!this.isAtEnd() && !this.isWordBreak(this.peek()) && this.peek() !== `
|
|
518
|
+
`) {
|
|
519
|
+
if (this.peek() === "\\") {
|
|
520
|
+
this.advance();
|
|
521
|
+
if (!this.isAtEnd()) {
|
|
522
|
+
delimiter += this.advance();
|
|
523
|
+
}
|
|
524
|
+
} else {
|
|
525
|
+
delimiter += this.advance();
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
return { delimiter, expand: true };
|
|
529
|
+
}
|
|
530
|
+
tokenizeRestOfLine() {
|
|
531
|
+
while (!this.isAtEnd() && this.peek() !== `
|
|
532
|
+
`) {
|
|
533
|
+
while (this.peek() === " " || this.peek() === "\t") {
|
|
534
|
+
this.advance();
|
|
535
|
+
}
|
|
536
|
+
if (this.isAtEnd() || this.peek() === `
|
|
537
|
+
`)
|
|
538
|
+
break;
|
|
539
|
+
const token = this.readRestOfLineToken();
|
|
540
|
+
if (token) {
|
|
541
|
+
this.tokenQueue.push(token);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
readRestOfLineToken() {
|
|
546
|
+
const char = this.peek();
|
|
547
|
+
if (char === "|") {
|
|
548
|
+
this.advance();
|
|
549
|
+
if (this.peek() === "|") {
|
|
550
|
+
this.advance();
|
|
551
|
+
return { type: "or" };
|
|
552
|
+
}
|
|
553
|
+
return { type: "pipe" };
|
|
554
|
+
}
|
|
555
|
+
if (char === "&") {
|
|
556
|
+
this.advance();
|
|
557
|
+
if (this.peek() === "&") {
|
|
558
|
+
this.advance();
|
|
559
|
+
return { type: "and" };
|
|
560
|
+
}
|
|
561
|
+
return { type: "word", value: "&" };
|
|
562
|
+
}
|
|
563
|
+
if (char === ";") {
|
|
564
|
+
this.advance();
|
|
565
|
+
return { type: "semicolon" };
|
|
566
|
+
}
|
|
567
|
+
if (char === ">") {
|
|
568
|
+
this.advance();
|
|
569
|
+
if (this.peek() === ">") {
|
|
570
|
+
this.advance();
|
|
571
|
+
return { type: "redirect", mode: ">>" };
|
|
572
|
+
}
|
|
573
|
+
return { type: "redirect", mode: ">" };
|
|
574
|
+
}
|
|
575
|
+
if (char === "<") {
|
|
576
|
+
this.advance();
|
|
577
|
+
return { type: "redirect", mode: "<" };
|
|
578
|
+
}
|
|
579
|
+
if (char === "$") {
|
|
580
|
+
return this.readVariable();
|
|
581
|
+
}
|
|
582
|
+
if (char === "'") {
|
|
583
|
+
return this.readSingleQuote();
|
|
584
|
+
}
|
|
585
|
+
if (char === '"') {
|
|
586
|
+
return this.readDoubleQuote();
|
|
587
|
+
}
|
|
588
|
+
let value = "";
|
|
589
|
+
while (!this.isAtEnd() && !this.isWordBreak(this.peek()) && this.peek() !== `
|
|
590
|
+
`) {
|
|
591
|
+
if (this.peek() === "\\") {
|
|
592
|
+
this.advance();
|
|
593
|
+
if (!this.isAtEnd()) {
|
|
594
|
+
value += this.advance();
|
|
595
|
+
}
|
|
596
|
+
} else {
|
|
597
|
+
value += this.advance();
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
if (value === "")
|
|
601
|
+
return null;
|
|
602
|
+
return { type: "word", value };
|
|
603
|
+
}
|
|
258
604
|
isWordBreak(char) {
|
|
259
605
|
return WORD_BREAK_CHARS.has(char);
|
|
260
606
|
}
|
|
@@ -266,6 +612,11 @@ class Lexer {
|
|
|
266
612
|
this.advance();
|
|
267
613
|
}
|
|
268
614
|
}
|
|
615
|
+
skipWhitespaceExceptNewlines() {
|
|
616
|
+
while (!this.isAtEnd() && /[ \t\r]/.test(this.peek())) {
|
|
617
|
+
this.advance();
|
|
618
|
+
}
|
|
619
|
+
}
|
|
269
620
|
skipComment() {
|
|
270
621
|
while (!this.isAtEnd() && this.peek() !== `
|
|
271
622
|
`) {
|
|
@@ -294,12 +645,12 @@ class Lexer {
|
|
|
294
645
|
return this.pos >= this.source.length;
|
|
295
646
|
}
|
|
296
647
|
}
|
|
297
|
-
function lex(source) {
|
|
298
|
-
return new Lexer(source).tokenize();
|
|
648
|
+
function lex(source, options) {
|
|
649
|
+
return new Lexer(source, options).tokenize();
|
|
299
650
|
}
|
|
300
651
|
export {
|
|
301
652
|
lex,
|
|
302
653
|
Lexer
|
|
303
654
|
};
|
|
304
655
|
|
|
305
|
-
//# debugId=
|
|
656
|
+
//# debugId=11B4DB819B360AA764756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lexer/lexer.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import { LexError } from \"../errors.mjs\";\nimport type { Token, RedirectMode } from \"./tokens.mjs\";\n\nconst GLOB_CHARS = new Set([\"*\", \"?\", \"[\", \"{\", \"}\"]);\nconst WORD_BREAK_CHARS = new Set([\n \" \",\n \"\\t\",\n \"\\n\",\n \"\\r\",\n \"|\",\n \"&\",\n \";\",\n \">\",\n \"<\",\n \"(\",\n \")\",\n \"$\",\n \"'\",\n '\"',\n \"`\",\n]);\n\nexport class Lexer {\n private source: string;\n private pos: number = 0;\n private line: number = 1;\n private column: number = 1;\n\n constructor(source: string) {\n this.source = source;\n }\n\n tokenize(): Token[] {\n const tokens: Token[] = [];\n\n while (!this.isAtEnd()) {\n this.skipWhitespace();\n if (this.isAtEnd()) break;\n\n const token = this.nextToken();\n if (token) {\n tokens.push(token);\n }\n }\n\n tokens.push({ type: \"eof\" });\n return tokens;\n }\n\n private nextToken(): Token | null {\n const char = this.peek();\n\n // Comments\n if (char === \"#\") {\n this.skipComment();\n return null;\n }\n\n // Operators and redirects\n if (char === \"|\") {\n this.advance();\n if (this.peek() === \"|\") {\n this.advance();\n return { type: \"or\" };\n }\n return { type: \"pipe\" };\n }\n\n if (char === \"&\") {\n this.advance();\n if (this.peek() === \"&\") {\n this.advance();\n return { type: \"and\" };\n }\n if (this.peek() === \">\") {\n this.advance();\n if (this.peek() === \">\") {\n this.advance();\n return { type: \"redirect\", mode: \"&>>\" };\n }\n return { type: \"redirect\", mode: \"&>\" };\n }\n // Background execution (&) - treat as word for now\n return { type: \"word\", value: \"&\" };\n }\n\n if (char === \";\") {\n this.advance();\n return { type: \"semicolon\" };\n }\n\n // Redirects\n if (char === \">\") {\n this.advance();\n if (this.peek() === \">\") {\n this.advance();\n return { type: \"redirect\", mode: \">>\" };\n }\n return { type: \"redirect\", mode: \">\" };\n }\n\n if (char === \"<\") {\n this.advance();\n return { type: \"redirect\", mode: \"<\" };\n }\n\n // File descriptor redirects (2>, 2>>, 2>&1, 1>&2)\n if (char === \"1\" || char === \"2\") {\n const fd = char;\n const nextChar = this.peekAhead(1);\n if (nextChar === \">\") {\n this.advance(); // consume fd\n this.advance(); // consume >\n if (fd === \"2\") {\n if (this.peek() === \"&\" && this.peekAhead(1) === \"1\") {\n this.advance(); // consume &\n this.advance(); // consume 1\n return { type: \"redirect\", mode: \"2>&1\" };\n }\n if (this.peek() === \">\") {\n this.advance();\n return { type: \"redirect\", mode: \"2>>\" };\n }\n return { type: \"redirect\", mode: \"2>\" };\n } else {\n // 1>&2\n if (this.peek() === \"&\" && this.peekAhead(1) === \"2\") {\n this.advance(); // consume &\n this.advance(); // consume 2\n return { type: \"redirect\", mode: \"1>&2\" };\n }\n if (this.peek() === \">\") {\n this.advance();\n return { type: \"redirect\", mode: \">>\" };\n }\n return { type: \"redirect\", mode: \">\" };\n }\n }\n }\n\n // Variables and substitutions\n if (char === \"$\") {\n return this.readVariable();\n }\n\n // Single quotes\n if (char === \"'\") {\n return this.readSingleQuote();\n }\n\n // Double quotes\n if (char === '\"') {\n return this.readDoubleQuote();\n }\n\n // Word (including potential globs and assignments)\n return this.readWord();\n }\n\n private readVariable(): Token {\n this.advance(); // consume $\n\n // Command substitution $(...)\n if (this.peek() === \"(\") {\n this.advance(); // consume (\n const command = this.readUntilMatchingParen();\n return { type: \"substitution\", command };\n }\n\n // ${VAR} syntax\n if (this.peek() === \"{\") {\n this.advance(); // consume {\n let name = \"\";\n while (!this.isAtEnd() && this.peek() !== \"}\") {\n name += this.advance();\n }\n if (this.peek() === \"}\") {\n this.advance(); // consume }\n }\n return { type: \"variable\", name };\n }\n\n // $VAR syntax\n let name = \"\";\n while (!this.isAtEnd() && this.isVarChar(this.peek())) {\n name += this.advance();\n }\n\n if (name === \"\") {\n return { type: \"word\", value: \"$\" };\n }\n\n return { type: \"variable\", name };\n }\n\n private readUntilMatchingParen(): string {\n let depth = 1;\n let result = \"\";\n\n while (!this.isAtEnd() && depth > 0) {\n const char = this.peek();\n if (char === \"(\") {\n depth++;\n } else if (char === \")\") {\n depth--;\n if (depth === 0) {\n this.advance(); // consume closing )\n break;\n }\n }\n result += this.advance();\n }\n\n return result;\n }\n\n private readSingleQuote(): Token {\n this.advance(); // consume opening '\n let value = \"\";\n\n while (!this.isAtEnd() && this.peek() !== \"'\") {\n value += this.advance();\n }\n\n if (this.peek() === \"'\") {\n this.advance(); // consume closing '\n } else {\n throw new LexError(\"Unterminated single quote\", this.pos, this.line, this.column);\n }\n\n return { type: \"singleQuote\", value };\n }\n\n private readDoubleQuote(): Token {\n this.advance(); // consume opening \"\n const parts: Array<string | Token> = [];\n let currentString = \"\";\n\n while (!this.isAtEnd() && this.peek() !== '\"') {\n const char = this.peek();\n\n if (char === \"\\\\\") {\n this.advance();\n if (!this.isAtEnd()) {\n const escaped = this.advance();\n // In double quotes, only certain chars are special\n if ([\"$\", '\"', \"\\\\\", \"`\", \"\\n\"].includes(escaped)) {\n currentString += escaped;\n } else {\n currentString += \"\\\\\" + escaped;\n }\n }\n } else if (char === \"$\") {\n if (currentString) {\n parts.push(currentString);\n currentString = \"\";\n }\n parts.push(this.readVariable());\n } else {\n currentString += this.advance();\n }\n }\n\n if (currentString) {\n parts.push(currentString);\n }\n\n if (this.peek() === '\"') {\n this.advance(); // consume closing \"\n } else {\n throw new LexError(\"Unterminated double quote\", this.pos, this.line, this.column);\n }\n\n return { type: \"doubleQuote\", parts };\n }\n\n private readWord(): Token {\n let value = \"\";\n let hasGlobChars = false;\n\n while (!this.isAtEnd() && !this.isWordBreak(this.peek())) {\n const char = this.peek();\n\n if (char === \"\\\\\") {\n this.advance();\n if (!this.isAtEnd()) {\n value += this.advance();\n }\n } else {\n if (GLOB_CHARS.has(char)) {\n hasGlobChars = true;\n }\n value += this.advance();\n }\n }\n\n // Check if this is an assignment (VAR=value)\n const assignmentMatch = value.match(/^([a-zA-Z_][a-zA-Z0-9_]*)=(.*)$/);\n if (assignmentMatch) {\n return {\n type: \"assignment\",\n name: assignmentMatch[1]!,\n value: assignmentMatch[2]!,\n };\n }\n\n if (hasGlobChars) {\n return { type: \"glob\", pattern: value };\n }\n\n return { type: \"word\", value };\n }\n\n private isWordBreak(char: string): boolean {\n return WORD_BREAK_CHARS.has(char);\n }\n\n private isVarChar(char: string): boolean {\n return /[a-zA-Z0-9_]/.test(char);\n }\n\n private skipWhitespace(): void {\n while (!this.isAtEnd() && /\\s/.test(this.peek())) {\n this.advance();\n }\n }\n\n private skipComment(): void {\n while (!this.isAtEnd() && this.peek() !== \"\\n\") {\n this.advance();\n }\n }\n\n private peek(): string {\n return this.source[this.pos] ?? \"\";\n }\n\n private peekAhead(n: number): string {\n return this.source[this.pos + n] ?? \"\";\n }\n\n private advance(): string {\n const char = this.source[this.pos]!;\n this.pos++;\n if (char === \"\\n\") {\n this.line++;\n this.column = 1;\n } else {\n this.column++;\n }\n return char;\n }\n\n private isAtEnd(): boolean {\n return this.pos >= this.source.length;\n }\n}\n\nexport function lex(source: string): Token[] {\n return new Lexer(source).tokenize();\n}\n"
|
|
5
|
+
"import { LexError } from \"../errors.mjs\";\nimport type { Token, RedirectMode, KeywordValue } from \"./tokens.mjs\";\nimport { KEYWORDS } from \"./tokens.mjs\";\n\nconst GLOB_CHARS = new Set([\"*\", \"?\", \"[\", \"{\", \"}\"]);\nconst WORD_BREAK_CHARS = new Set([\n \" \",\n \"\\t\",\n \"\\n\",\n \"\\r\",\n \"|\",\n \"&\",\n \";\",\n \">\",\n \"<\",\n \"(\",\n \")\",\n \"$\",\n \"'\",\n '\"',\n \"`\",\n]);\n\nexport class Lexer {\n private source: string;\n private pos: number = 0;\n private line: number = 1;\n private column: number = 1;\n private tokenQueue: Token[] = [];\n private preserveNewlines: boolean;\n\n constructor(source: string, options?: { preserveNewlines?: boolean }) {\n this.source = source;\n this.preserveNewlines = options?.preserveNewlines ?? false;\n }\n\n tokenize(): Token[] {\n const tokens: Token[] = [];\n\n while (!this.isAtEnd() || this.tokenQueue.length > 0) {\n // Drain token queue first (for heredoc handling)\n if (this.tokenQueue.length > 0) {\n tokens.push(this.tokenQueue.shift()!);\n continue;\n }\n\n this.skipWhitespaceExceptNewlines();\n if (this.isAtEnd()) break;\n\n const token = this.nextToken();\n if (token) {\n tokens.push(token);\n }\n }\n\n tokens.push({ type: \"eof\" });\n return tokens;\n }\n\n private nextToken(): Token | null {\n // Check token queue first (used for heredoc handling)\n if (this.tokenQueue.length > 0) {\n return this.tokenQueue.shift()!;\n }\n\n const char = this.peek();\n\n // Newlines - significant for control flow\n if (char === \"\\n\") {\n this.advance();\n // Skip consecutive newlines\n while (this.peek() === \"\\n\") {\n this.advance();\n }\n if (this.preserveNewlines) {\n return { type: \"newline\" };\n }\n return null;\n }\n\n // Comments\n if (char === \"#\") {\n this.skipComment();\n return null;\n }\n\n // Parentheses - for case pattern grouping\n if (char === \"(\") {\n this.advance();\n return { type: \"openParen\" };\n }\n\n if (char === \")\") {\n this.advance();\n return { type: \"closeParen\" };\n }\n\n // Operators and redirects\n if (char === \"|\") {\n this.advance();\n if (this.peek() === \"|\") {\n this.advance();\n return { type: \"or\" };\n }\n return { type: \"pipe\" };\n }\n\n if (char === \"&\") {\n this.advance();\n if (this.peek() === \"&\") {\n this.advance();\n return { type: \"and\" };\n }\n if (this.peek() === \">\") {\n this.advance();\n if (this.peek() === \">\") {\n this.advance();\n return { type: \"redirect\", mode: \"&>>\" };\n }\n return { type: \"redirect\", mode: \"&>\" };\n }\n // Background execution (&) - treat as word for now\n return { type: \"word\", value: \"&\" };\n }\n\n if (char === \";\") {\n this.advance();\n // Check for double semicolon (case terminator)\n if (this.peek() === \";\") {\n this.advance();\n return { type: \"doubleSemicolon\" };\n }\n return { type: \"semicolon\" };\n }\n\n // Redirects\n if (char === \">\") {\n this.advance();\n if (this.peek() === \">\") {\n this.advance();\n return { type: \"redirect\", mode: \">>\" };\n }\n return { type: \"redirect\", mode: \">\" };\n }\n\n if (char === \"<\") {\n this.advance();\n if (this.peek() === \"<\") {\n this.advance();\n return this.readHeredoc();\n }\n return { type: \"redirect\", mode: \"<\" };\n }\n\n // File descriptor redirects (2>, 2>>, 2>&1, 1>&2)\n if (char === \"1\" || char === \"2\") {\n const fd = char;\n const nextChar = this.peekAhead(1);\n if (nextChar === \">\") {\n this.advance(); // consume fd\n this.advance(); // consume >\n if (fd === \"2\") {\n if (this.peek() === \"&\" && this.peekAhead(1) === \"1\") {\n this.advance(); // consume &\n this.advance(); // consume 1\n return { type: \"redirect\", mode: \"2>&1\" };\n }\n if (this.peek() === \">\") {\n this.advance();\n return { type: \"redirect\", mode: \"2>>\" };\n }\n return { type: \"redirect\", mode: \"2>\" };\n } else {\n // 1>&2\n if (this.peek() === \"&\" && this.peekAhead(1) === \"2\") {\n this.advance(); // consume &\n this.advance(); // consume 2\n return { type: \"redirect\", mode: \"1>&2\" };\n }\n if (this.peek() === \">\") {\n this.advance();\n return { type: \"redirect\", mode: \">>\" };\n }\n return { type: \"redirect\", mode: \">\" };\n }\n }\n }\n\n // Variables and substitutions\n if (char === \"$\") {\n return this.readVariable();\n }\n\n // Single quotes\n if (char === \"'\") {\n return this.readSingleQuote();\n }\n\n // Double quotes\n if (char === '\"') {\n return this.readDoubleQuote();\n }\n\n // Word (including potential globs and assignments)\n return this.readWord();\n }\n\n private readVariable(): Token {\n this.advance(); // consume $\n\n // Arithmetic expansion $((...)) or command substitution $(...)\n if (this.peek() === \"(\") {\n this.advance(); // consume first (\n // Check for arithmetic expansion $((...))\n if (this.peek() === \"(\") {\n this.advance(); // consume second (\n const expression = this.readUntilDoubleCloseParen();\n return { type: \"arithmetic\", expression };\n }\n const command = this.readUntilMatchingParen();\n return { type: \"substitution\", command };\n }\n\n // ${VAR} syntax\n if (this.peek() === \"{\") {\n this.advance(); // consume {\n let name = \"\";\n while (!this.isAtEnd() && this.peek() !== \"}\") {\n name += this.advance();\n }\n if (this.peek() === \"}\") {\n this.advance(); // consume }\n }\n return { type: \"variable\", name };\n }\n\n // $VAR syntax\n let name = \"\";\n while (!this.isAtEnd() && this.isVarChar(this.peek())) {\n name += this.advance();\n }\n\n if (name === \"\") {\n return { type: \"word\", value: \"$\" };\n }\n\n return { type: \"variable\", name };\n }\n\n private readUntilDoubleCloseParen(): string {\n let depth = 1;\n let result = \"\";\n\n while (!this.isAtEnd() && depth > 0) {\n const char = this.peek();\n if (char === \"(\" && this.peekAhead(1) === \"(\") {\n depth++;\n result += this.advance();\n result += this.advance();\n } else if (char === \")\" && this.peekAhead(1) === \")\") {\n depth--;\n if (depth === 0) {\n this.advance(); // consume first )\n this.advance(); // consume second )\n break;\n }\n result += this.advance();\n result += this.advance();\n } else {\n result += this.advance();\n }\n }\n\n return result;\n }\n\n private readUntilMatchingParen(): string {\n let depth = 1;\n let result = \"\";\n\n while (!this.isAtEnd() && depth > 0) {\n const char = this.peek();\n if (char === \"(\") {\n depth++;\n } else if (char === \")\") {\n depth--;\n if (depth === 0) {\n this.advance(); // consume closing )\n break;\n }\n }\n result += this.advance();\n }\n\n return result;\n }\n\n private readSingleQuote(): Token {\n this.advance(); // consume opening '\n let value = \"\";\n\n while (!this.isAtEnd() && this.peek() !== \"'\") {\n value += this.advance();\n }\n\n if (this.peek() === \"'\") {\n this.advance(); // consume closing '\n } else {\n throw new LexError(\"Unterminated single quote\", this.pos, this.line, this.column);\n }\n\n return { type: \"singleQuote\", value };\n }\n\n private readDoubleQuote(): Token {\n this.advance(); // consume opening \"\n const parts: Array<string | Token> = [];\n let currentString = \"\";\n\n while (!this.isAtEnd() && this.peek() !== '\"') {\n const char = this.peek();\n\n if (char === \"\\\\\") {\n this.advance();\n if (!this.isAtEnd()) {\n const escaped = this.advance();\n // In double quotes, only certain chars are special\n if ([\"$\", '\"', \"\\\\\", \"`\", \"\\n\"].includes(escaped)) {\n currentString += escaped;\n } else {\n currentString += \"\\\\\" + escaped;\n }\n }\n } else if (char === \"$\") {\n if (currentString) {\n parts.push(currentString);\n currentString = \"\";\n }\n parts.push(this.readVariable());\n } else {\n currentString += this.advance();\n }\n }\n\n if (currentString) {\n parts.push(currentString);\n }\n\n if (this.peek() === '\"') {\n this.advance(); // consume closing \"\n } else {\n throw new LexError(\"Unterminated double quote\", this.pos, this.line, this.column);\n }\n\n return { type: \"doubleQuote\", parts };\n }\n\n private readWord(): Token {\n let value = \"\";\n let hasGlobChars = false;\n\n while (!this.isAtEnd() && !this.isWordBreak(this.peek())) {\n const char = this.peek();\n\n if (char === \"\\\\\") {\n this.advance();\n if (!this.isAtEnd()) {\n value += this.advance();\n }\n } else {\n if (GLOB_CHARS.has(char)) {\n hasGlobChars = true;\n }\n value += this.advance();\n }\n }\n\n // Check if this looks like an assignment with value starting with $ or quote\n // e.g., VAR=$(...) or VAR=\"...\" or VAR='...'\n const assignmentPrefixMatch = value.match(/^([a-zA-Z_][a-zA-Z0-9_]*)=$/);\n if (assignmentPrefixMatch && (this.peek() === \"$\" || this.peek() === \"'\" || this.peek() === '\"')) {\n const name = assignmentPrefixMatch[1]!;\n // Read the value part\n const valueTokens = this.readAssignmentValueTokens();\n return {\n type: \"assignment\",\n name,\n value: valueTokens.length === 1 && valueTokens[0]!.type === \"word\"\n ? (valueTokens[0] as { type: \"word\"; value: string }).value\n : valueTokens,\n };\n }\n\n // Check if this is an assignment (VAR=value)\n const assignmentMatch = value.match(/^([a-zA-Z_][a-zA-Z0-9_]*)=(.*)$/);\n if (assignmentMatch) {\n const name = assignmentMatch[1]!;\n const rawValue = assignmentMatch[2]!;\n\n // Parse the value to handle variables and arithmetic\n const parsedValue = this.parseAssignmentValue(rawValue);\n return {\n type: \"assignment\",\n name,\n value: parsedValue,\n };\n }\n\n // Check if this is a keyword\n if (KEYWORDS.has(value)) {\n return { type: \"keyword\", value: value as KeywordValue };\n }\n\n if (hasGlobChars) {\n return { type: \"glob\", pattern: value };\n }\n\n return { type: \"word\", value };\n }\n\n private readAssignmentValueTokens(): Token[] {\n const tokens: Token[] = [];\n\n // Read tokens until we hit a space, newline, semicolon, etc.\n while (!this.isAtEnd()) {\n const char = this.peek();\n\n // Stop at whitespace or command terminators\n if (char === \" \" || char === \"\\t\" || char === \"\\n\" || char === \"\\r\" ||\n char === \";\" || char === \"|\" || char === \"&\" || char === \">\" || char === \"<\") {\n break;\n }\n\n if (char === \"$\") {\n tokens.push(this.readVariable());\n } else if (char === \"'\") {\n tokens.push(this.readSingleQuote());\n } else if (char === '\"') {\n tokens.push(this.readDoubleQuote());\n } else {\n // Read until word break\n let word = \"\";\n while (!this.isAtEnd() && !this.isWordBreak(this.peek())) {\n word += this.advance();\n }\n if (word) {\n tokens.push({ type: \"word\", value: word });\n } else {\n break;\n }\n }\n }\n\n return tokens;\n }\n\n private parseAssignmentValue(value: string): string | Token[] {\n // If value contains no special characters, return as string\n if (!value.includes(\"$\")) {\n return value;\n }\n\n // Parse the value to handle $VAR, ${VAR}, $((expr))\n const tokens: Token[] = [];\n let i = 0;\n let currentString = \"\";\n\n while (i < value.length) {\n if (value[i] === \"$\") {\n if (currentString) {\n tokens.push({ type: \"word\", value: currentString });\n currentString = \"\";\n }\n\n i++; // consume $\n if (i >= value.length) {\n tokens.push({ type: \"word\", value: \"$\" });\n break;\n }\n\n // Arithmetic expansion $((expr))\n if (value[i] === \"(\" && value[i + 1] === \"(\") {\n i += 2; // consume ((\n let depth = 1;\n let expr = \"\";\n while (i < value.length && depth > 0) {\n if (value[i] === \"(\" && value[i + 1] === \"(\") {\n depth++;\n expr += value[i]! + value[i + 1]!;\n i += 2;\n } else if (value[i] === \")\" && value[i + 1] === \")\") {\n depth--;\n if (depth > 0) {\n expr += value[i]! + value[i + 1]!;\n i += 2;\n } else {\n i += 2; // consume ))\n }\n } else {\n expr += value[i];\n i++;\n }\n }\n tokens.push({ type: \"arithmetic\", expression: expr });\n }\n // ${VAR} syntax\n else if (value[i] === \"{\") {\n i++; // consume {\n let varName = \"\";\n while (i < value.length && value[i] !== \"}\") {\n varName += value[i];\n i++;\n }\n if (i < value.length && value[i] === \"}\") {\n i++; // consume }\n }\n tokens.push({ type: \"variable\", name: varName });\n }\n // $VAR syntax\n else if (/[a-zA-Z_]/.test(value[i]!)) {\n let varName = \"\";\n while (i < value.length && /[a-zA-Z0-9_]/.test(value[i]!)) {\n varName += value[i];\n i++;\n }\n tokens.push({ type: \"variable\", name: varName });\n }\n // $(cmd) command substitution\n else if (value[i] === \"(\") {\n i++; // consume (\n let depth = 1;\n let cmd = \"\";\n while (i < value.length && depth > 0) {\n if (value[i] === \"(\") depth++;\n else if (value[i] === \")\") depth--;\n if (depth > 0) {\n cmd += value[i];\n }\n i++;\n }\n tokens.push({ type: \"substitution\", command: cmd });\n }\n else {\n // Not a variable, just a $\n currentString += \"$\";\n }\n } else {\n currentString += value[i];\n i++;\n }\n }\n\n if (currentString) {\n tokens.push({ type: \"word\", value: currentString });\n }\n\n if (tokens.length === 1 && tokens[0]!.type === \"word\") {\n return (tokens[0] as { type: \"word\"; value: string }).value;\n }\n\n return tokens.length > 0 ? tokens : value;\n }\n\n private readHeredoc(): Token {\n // Check for tab-stripping variant (<<-)\n const stripTabs = this.peek() === \"-\";\n if (stripTabs) {\n this.advance();\n }\n\n // Skip whitespace before delimiter\n while (this.peek() === \" \" || this.peek() === \"\\t\") {\n this.advance();\n }\n\n // Read delimiter and determine if expansion is enabled\n const { delimiter, expand } = this.readHeredocDelimiter();\n\n // Tokenize the rest of the current line and queue those tokens\n this.tokenizeRestOfLine();\n\n // Skip the newline that starts the heredoc content\n if (this.peek() === \"\\n\") {\n this.advance();\n }\n\n // Read content until closing delimiter\n let content = \"\";\n while (!this.isAtEnd()) {\n const lineStart = this.pos;\n let line = \"\";\n\n // Read until end of line or end of input\n while (!this.isAtEnd() && this.peek() !== \"\\n\") {\n line += this.advance();\n }\n\n // Check if this line is the delimiter (after stripping leading tabs if <<-)\n const strippedLine = stripTabs ? line.replace(/^\\t+/, \"\") : line;\n if (strippedLine === delimiter) {\n // Found closing delimiter, consume newline if present\n if (this.peek() === \"\\n\") {\n this.advance();\n }\n break;\n }\n\n // Add the line to content\n if (stripTabs) {\n content += line.replace(/^\\t+/, \"\");\n } else {\n content += line;\n }\n\n // Add newline if present\n if (this.peek() === \"\\n\") {\n content += this.advance();\n }\n }\n\n return { type: \"heredoc\", content, expand };\n }\n\n private readHeredocDelimiter(): { delimiter: string; expand: boolean } {\n const quoteChar = this.peek();\n\n // Quoted delimiter - no expansion\n if (quoteChar === \"'\" || quoteChar === '\"') {\n this.advance(); // consume opening quote\n let delimiter = \"\";\n while (!this.isAtEnd() && this.peek() !== quoteChar && this.peek() !== \"\\n\") {\n delimiter += this.advance();\n }\n if (this.peek() === quoteChar) {\n this.advance(); // consume closing quote\n }\n return { delimiter, expand: false };\n }\n\n // Unquoted delimiter - expansion enabled\n let delimiter = \"\";\n while (!this.isAtEnd() && !this.isWordBreak(this.peek()) && this.peek() !== \"\\n\") {\n if (this.peek() === \"\\\\\") {\n this.advance();\n if (!this.isAtEnd()) {\n delimiter += this.advance();\n }\n } else {\n delimiter += this.advance();\n }\n }\n\n return { delimiter, expand: true };\n }\n\n private tokenizeRestOfLine(): void {\n // Tokenize the rest of the line (until newline or end)\n while (!this.isAtEnd() && this.peek() !== \"\\n\") {\n // Skip only spaces and tabs, not newlines\n while (this.peek() === \" \" || this.peek() === \"\\t\") {\n this.advance();\n }\n if (this.isAtEnd() || this.peek() === \"\\n\") break;\n\n const token = this.readRestOfLineToken();\n if (token) {\n this.tokenQueue.push(token);\n }\n }\n }\n\n private readRestOfLineToken(): Token | null {\n const char = this.peek();\n\n if (char === \"|\") {\n this.advance();\n if (this.peek() === \"|\") {\n this.advance();\n return { type: \"or\" };\n }\n return { type: \"pipe\" };\n }\n\n if (char === \"&\") {\n this.advance();\n if (this.peek() === \"&\") {\n this.advance();\n return { type: \"and\" };\n }\n return { type: \"word\", value: \"&\" };\n }\n\n if (char === \";\") {\n this.advance();\n return { type: \"semicolon\" };\n }\n\n if (char === \">\") {\n this.advance();\n if (this.peek() === \">\") {\n this.advance();\n return { type: \"redirect\", mode: \">>\" };\n }\n return { type: \"redirect\", mode: \">\" };\n }\n\n if (char === \"<\") {\n this.advance();\n return { type: \"redirect\", mode: \"<\" };\n }\n\n if (char === \"$\") {\n return this.readVariable();\n }\n\n if (char === \"'\") {\n return this.readSingleQuote();\n }\n\n if (char === '\"') {\n return this.readDoubleQuote();\n }\n\n // Read a word but stop at newline\n let value = \"\";\n while (!this.isAtEnd() && !this.isWordBreak(this.peek()) && this.peek() !== \"\\n\") {\n if (this.peek() === \"\\\\\") {\n this.advance();\n if (!this.isAtEnd()) {\n value += this.advance();\n }\n } else {\n value += this.advance();\n }\n }\n\n if (value === \"\") return null;\n return { type: \"word\", value };\n }\n\n private isWordBreak(char: string): boolean {\n return WORD_BREAK_CHARS.has(char);\n }\n\n private isVarChar(char: string): boolean {\n return /[a-zA-Z0-9_]/.test(char);\n }\n\n private skipWhitespace(): void {\n while (!this.isAtEnd() && /\\s/.test(this.peek())) {\n this.advance();\n }\n }\n\n private skipWhitespaceExceptNewlines(): void {\n while (!this.isAtEnd() && /[ \\t\\r]/.test(this.peek())) {\n this.advance();\n }\n }\n\n private skipComment(): void {\n while (!this.isAtEnd() && this.peek() !== \"\\n\") {\n this.advance();\n }\n }\n\n private peek(): string {\n return this.source[this.pos] ?? \"\";\n }\n\n private peekAhead(n: number): string {\n return this.source[this.pos + n] ?? \"\";\n }\n\n private advance(): string {\n const char = this.source[this.pos]!;\n this.pos++;\n if (char === \"\\n\") {\n this.line++;\n this.column = 1;\n } else {\n this.column++;\n }\n return char;\n }\n\n private isAtEnd(): boolean {\n return this.pos >= this.source.length;\n }\n}\n\nexport function lex(source: string, options?: { preserveNewlines?: boolean }): Token[] {\n return new Lexer(source, options).tokenize();\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": "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",
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "11B4DB819B360AA764756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -1,8 +1,25 @@
|
|
|
1
1
|
// src/lexer/tokens.ts
|
|
2
|
+
var KEYWORDS = new Set([
|
|
3
|
+
"if",
|
|
4
|
+
"then",
|
|
5
|
+
"elif",
|
|
6
|
+
"else",
|
|
7
|
+
"fi",
|
|
8
|
+
"for",
|
|
9
|
+
"in",
|
|
10
|
+
"do",
|
|
11
|
+
"done",
|
|
12
|
+
"while",
|
|
13
|
+
"until",
|
|
14
|
+
"case",
|
|
15
|
+
"esac"
|
|
16
|
+
]);
|
|
2
17
|
function tokenToString(token) {
|
|
3
18
|
switch (token.type) {
|
|
4
19
|
case "word":
|
|
5
20
|
return token.value;
|
|
21
|
+
case "keyword":
|
|
22
|
+
return token.value;
|
|
6
23
|
case "pipe":
|
|
7
24
|
return "|";
|
|
8
25
|
case "and":
|
|
@@ -11,12 +28,17 @@ function tokenToString(token) {
|
|
|
11
28
|
return "||";
|
|
12
29
|
case "semicolon":
|
|
13
30
|
return ";";
|
|
31
|
+
case "newline":
|
|
32
|
+
return `
|
|
33
|
+
`;
|
|
14
34
|
case "redirect":
|
|
15
35
|
return token.mode;
|
|
16
36
|
case "variable":
|
|
17
37
|
return `$${token.name}`;
|
|
18
38
|
case "substitution":
|
|
19
39
|
return `$(${token.command})`;
|
|
40
|
+
case "arithmetic":
|
|
41
|
+
return `$((${token.expression}))`;
|
|
20
42
|
case "glob":
|
|
21
43
|
return token.pattern;
|
|
22
44
|
case "singleQuote":
|
|
@@ -25,12 +47,23 @@ function tokenToString(token) {
|
|
|
25
47
|
return `"${token.parts.map((p) => typeof p === "string" ? p : tokenToString(p)).join("")}"`;
|
|
26
48
|
case "assignment":
|
|
27
49
|
return `${token.name}=${typeof token.value === "string" ? token.value : token.value.map(tokenToString).join("")}`;
|
|
50
|
+
case "heredoc":
|
|
51
|
+
return `<<${token.expand ? "EOF" : "'EOF'"}
|
|
52
|
+
${token.content}
|
|
53
|
+
EOF`;
|
|
54
|
+
case "openParen":
|
|
55
|
+
return "(";
|
|
56
|
+
case "closeParen":
|
|
57
|
+
return ")";
|
|
58
|
+
case "doubleSemicolon":
|
|
59
|
+
return ";;";
|
|
28
60
|
case "eof":
|
|
29
61
|
return "<EOF>";
|
|
30
62
|
}
|
|
31
63
|
}
|
|
32
64
|
export {
|
|
33
|
-
tokenToString
|
|
65
|
+
tokenToString,
|
|
66
|
+
KEYWORDS
|
|
34
67
|
};
|
|
35
68
|
|
|
36
|
-
//# debugId=
|
|
69
|
+
//# debugId=6DFA4E9D27E55DE464756E2164756E21
|