* Parse a simple command: [assignment]* word [arg|redirect]* * Returns variable_assignment if only one assignment and no command.
(P: ParseState)
| 1139 | * Returns variable_assignment if only one assignment and no command. |
| 1140 | */ |
| 1141 | function parseSimpleCommand(P: ParseState): TsNode | null { |
| 1142 | const start = P.L.b |
| 1143 | const assignments: TsNode[] = [] |
| 1144 | const preRedirects: TsNode[] = [] |
| 1145 | |
| 1146 | while (true) { |
| 1147 | skipBlanks(P.L) |
| 1148 | const a = tryParseAssignment(P) |
| 1149 | if (a) { |
| 1150 | assignments.push(a) |
| 1151 | continue |
| 1152 | } |
| 1153 | const r = tryParseRedirect(P) |
| 1154 | if (r) { |
| 1155 | preRedirects.push(r) |
| 1156 | continue |
| 1157 | } |
| 1158 | break |
| 1159 | } |
| 1160 | |
| 1161 | skipBlanks(P.L) |
| 1162 | const save = saveLex(P.L) |
| 1163 | const nameTok = nextToken(P.L, 'cmd') |
| 1164 | if ( |
| 1165 | nameTok.type === 'EOF' || |
| 1166 | nameTok.type === 'NEWLINE' || |
| 1167 | nameTok.type === 'COMMENT' || |
| 1168 | (nameTok.type === 'OP' && |
| 1169 | nameTok.value !== '{' && |
| 1170 | nameTok.value !== '[' && |
| 1171 | nameTok.value !== '[[') || |
| 1172 | (nameTok.type === 'WORD' && |
| 1173 | SHELL_KEYWORDS.has(nameTok.value) && |
| 1174 | nameTok.value !== 'in') |
| 1175 | ) { |
| 1176 | restoreLex(P.L, save) |
| 1177 | // No command — standalone assignment(s) or redirect |
| 1178 | if (assignments.length === 1 && preRedirects.length === 0) { |
| 1179 | return assignments[0]! |
| 1180 | } |
| 1181 | if (preRedirects.length > 0 && assignments.length === 0) { |
| 1182 | // Bare redirect → redirected_statement with just file_redirect children |
| 1183 | const last = preRedirects[preRedirects.length - 1]! |
| 1184 | return mk( |
| 1185 | P, |
| 1186 | 'redirected_statement', |
| 1187 | preRedirects[0]!.startIndex, |
| 1188 | last.endIndex, |
| 1189 | preRedirects, |
| 1190 | ) |
| 1191 | } |
| 1192 | if (assignments.length > 1 && preRedirects.length === 0) { |
| 1193 | // `A=1 B=2` with no command → variable_assignments (plural) |
| 1194 | const last = assignments[assignments.length - 1]! |
| 1195 | return mk( |
| 1196 | P, |
| 1197 | 'variable_assignments', |
| 1198 | assignments[0]!.startIndex, |
no test coverage detected