| 2157 | } |
| 2158 | |
| 2159 | function parseBareWord(P: ParseState): TsNode | null { |
| 2160 | const start = P.L.b |
| 2161 | const startI = P.L.i |
| 2162 | while (P.L.i < P.L.len) { |
| 2163 | const c = peek(P.L) |
| 2164 | if (c === '\\') { |
| 2165 | if (P.L.i + 1 >= P.L.len) { |
| 2166 | // Trailing unpaired `\` at true EOF — tree-sitter emits word WITHOUT |
| 2167 | // the `\` plus a sibling ERROR node. Stop here; caller emits ERROR. |
| 2168 | break |
| 2169 | } |
| 2170 | const nx = P.L.src[P.L.i + 1] |
| 2171 | if (nx === '\n' || (nx === '\r' && P.L.src[P.L.i + 2] === '\n')) { |
| 2172 | // Line continuation BREAKS the word (tree-sitter quirk) — handles \r?\n |
| 2173 | break |
| 2174 | } |
| 2175 | advance(P.L) |
| 2176 | advance(P.L) |
| 2177 | continue |
| 2178 | } |
| 2179 | if ( |
| 2180 | c === ' ' || |
| 2181 | c === '\t' || |
| 2182 | c === '\n' || |
| 2183 | c === '\r' || |
| 2184 | c === '' || |
| 2185 | c === '|' || |
| 2186 | c === '&' || |
| 2187 | c === ';' || |
| 2188 | c === '(' || |
| 2189 | c === ')' || |
| 2190 | c === '<' || |
| 2191 | c === '>' || |
| 2192 | c === '"' || |
| 2193 | c === "'" || |
| 2194 | c === '$' || |
| 2195 | c === '`' || |
| 2196 | c === '{' || |
| 2197 | c === '}' || |
| 2198 | c === '[' || |
| 2199 | c === ']' |
| 2200 | ) { |
| 2201 | break |
| 2202 | } |
| 2203 | advance(P.L) |
| 2204 | } |
| 2205 | if (P.L.b === start) return null |
| 2206 | const text = P.src.slice(startI, P.L.i) |
| 2207 | const type = /^-?\d+$/.test(text) ? 'number' : 'word' |
| 2208 | return mk(P, type, start, P.L.b, []) |
| 2209 | } |
| 2210 | |
| 2211 | function tryParseBraceExpr(P: ParseState): TsNode | null { |
| 2212 | // {N..M} where N, M are numbers or single chars |