46 lines
1.6 KiB
JavaScript
46 lines
1.6 KiB
JavaScript
/**
|
|
* Shell tokenizer slice (diagnostics / trace); planner and executor use {@link ./shell-lex.js}.
|
|
*/
|
|
import { lexShellLine } from './shell-lex.js'
|
|
|
|
export function tokenizeBareShellLineForDiagnostics(line) {
|
|
const toks = tokenizeBareShellLineDetailed(line)
|
|
return toks.map((t) => ({ type: 'word', value: t.value }))
|
|
}
|
|
|
|
/**
|
|
* Structured token stream for diagnostics and grammar development.
|
|
* @param {string} line
|
|
* @returns {{ type: 'word', value: string, mode: 'normal'|'single'|'double'|'arith'|'heredoc'|'op', start: number, end: number }[]}
|
|
*/
|
|
export function tokenizeBareShellLineDetailed(line) {
|
|
const raw = lexShellLine(String(line || ''))
|
|
/** @type {{ type: 'word', value: string, mode: 'normal'|'single'|'double'|'arith'|'heredoc'|'op', start: number, end: number }[]} */
|
|
const out = []
|
|
for (const t of raw) {
|
|
const st = t.start ?? 0
|
|
const en = t.end ?? st
|
|
if (t.type === 'op') {
|
|
const v = t.value
|
|
let mode = /** @type {'normal'|'heredoc'} */ ('normal')
|
|
if (v === '<<' || v === '<<-' || v === '<<<') mode = 'heredoc'
|
|
out.push({ type: 'word', value: v, mode, start: st, end: en })
|
|
continue
|
|
}
|
|
const parts = t.parts || []
|
|
const joined = parts.map((p) => p.t).join('')
|
|
let mode = /** @type {'normal'|'single'|'double'|'arith'} */ ('normal')
|
|
if (parts.length === 1 && parts[0].q === 's') mode = 'single'
|
|
else if (parts.length === 1 && parts[0].q === 'd') mode = 'double'
|
|
if (/\$\(\(/.test(joined)) mode = 'arith'
|
|
out.push({
|
|
type: 'word',
|
|
value: t.value,
|
|
mode,
|
|
start: st,
|
|
end: en
|
|
})
|
|
}
|
|
return out
|
|
}
|