Files
bare-operating-system/packages/bare-os-booter/lib/shell/shell-tokenizer.js
T
2026-08-18 18:11:28 -04:00

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
}