import { Parser, Result, Input } from '../parser'; import { matcher } from '../delimiter'; import { always } from '../control/state'; import { clear } from './clear'; export function focus

(scope: string | RegExp, parser: P, slice?: boolean): P; export function focus(scope: string | RegExp, parser: Parser, slice = true): Parser { assert(parser); interface Memory { readonly position: number; readonly range: number; } const match = matcher(scope, slice); return always>>([ (input, output) => { const { source, position } = input; if (position === source.length) return Result.skip; const src = match(input, output) ?? ''; assert(source.startsWith(src, position)); if (src === '') { input.position = position; return Result.skip; } input.range = src.length; if (slice) { input.scope.focus(src); } else { input.memory = { position, range: input.range, }; } return output.context; }, parser, (input, output) => { if (slice) { input.scope.unfocus(output.state, true); } else { input.position += output.state && input.position === input.memory.position ? input.memory.range : 0; } return output.context; }, ]); } export function rewrite

(scope: Parser>, parser: P, slice?: boolean): P; export function rewrite(scope: Parser, parser: Parser, slice = true): Parser { assert(scope); assert(parser); interface Memory { readonly position: number; range: number; readonly linebreak: number; } return always>>([ (input, output) => { const { source, position, linebreak } = input; if (position === source.length) return Result.skip; input.memory = { position, range: 0, linebreak, }; return output.context; }, clear(scope), (input, output) => { const { source, position, memory } = input; const range = position - memory.position; input.range = memory.range = range; input.linebreak = memory.linebreak; if (!output.state || range === 0) { input.position = memory.position; return Result.skip; } if (slice) { input.scope.focus(source.slice(position - range, position)); } else { input.position -= range; } return output.context; }, parser, (input, output) => { if (slice) { input.scope.unfocus(output.state, true); } else { input.position += output.state && input.position === input.memory.position ? input.memory.range : 0; } return output.context; }, ]); }