import { Parser, Result, Input } from '../parser';
import { always } from '../control/state';
export function line
(parser: P, slice?: boolean): P;
export function line(parser: Parser, slice: boolean = true): Parser {
assert(parser);
interface Memory {
readonly position: number;
}
return always>>([
(input, output) => {
const { source, position } = input;
if (position === source.length) return Result.skip;
input.memory = {
position,
};
if (slice) {
const line = firstline(source, position);
input.position += line.length;
input.scope.focus(line);
}
return output.context;
},
parser,
(input, output) => {
if (slice) {
input.scope.unfocus(output.state, true);
}
if (!output.state) return;
const { source, position, memory } = input;
if (position === memory.position || position !== source.length && source[position - 1] !== '\n' && isEmptyline(source, position)) {
input.position = source.indexOf('\n', position) + 1 || source.length;
}
return output.state && (input.position === source.length || source[input.position - 1] === '\n')
? output.context
: Result.fail;
},
]);
}
export function firstline(source: string, position: number): string {
if (position === source.length) return '';
const i = source.indexOf('\n', position);
return i === -1
? source.slice(position)
: source.slice(position, i + 1);
}
const emptyline = /[^\S\r\n]*(?:$|\r?\n)/y;
export function isEmptyline(source: string, position: number): boolean {
emptyline.lastIndex = position;
return position >= source.length
|| source[position] === '\n'
|| emptyline.test(source);
}