Introduce recognizers
This commit is contained in:
parent
a56020cd9f
commit
bb9ca93f4e
4 changed files with 91 additions and 16 deletions
70
src/recognizers.ts
Normal file
70
src/recognizers.ts
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
import type { CodePoint, CodePointSpan, CodePointString, SourceCursor } from 'source-region';
|
||||
|
||||
export type TextMatch =
|
||||
| { tag: "match"; span: CodePointSpan; text: string }
|
||||
| { tag: "none" };
|
||||
|
||||
export namespace TextMatch {
|
||||
export function match(span: CodePointSpan, text: string): TextMatch {
|
||||
return { tag: "match", span, text };
|
||||
}
|
||||
|
||||
export function none(): TextMatch {
|
||||
return { tag: "none" };
|
||||
}
|
||||
}
|
||||
|
||||
export function consumeWhile(
|
||||
cursor: SourceCursor,
|
||||
predicate: (cp: CodePoint) => boolean,
|
||||
): CodePointSpan {
|
||||
const start = cursor.checkpoint();
|
||||
|
||||
while (true) {
|
||||
const cp = cursor.peek();
|
||||
if (cp === undefined || !predicate(cp)) break;
|
||||
cursor.advance();
|
||||
}
|
||||
|
||||
return cursor.spanFrom(start);
|
||||
}
|
||||
|
||||
export function consumeWhile1(
|
||||
cursor: SourceCursor,
|
||||
predicate: (cp: CodePoint) => boolean,
|
||||
): TextMatch {
|
||||
const start = cursor.checkpoint();
|
||||
const span = consumeWhile(cursor, predicate);
|
||||
|
||||
if (span.start === span.end) {
|
||||
cursor.restore(start);
|
||||
return TextMatch.none();
|
||||
}
|
||||
|
||||
return TextMatch.match(span, cursor.slice(span));
|
||||
}
|
||||
|
||||
export function skipWhile(
|
||||
cursor: SourceCursor,
|
||||
predicate: (cp: CodePoint) => boolean,
|
||||
): CodePointSpan {
|
||||
return consumeWhile(cursor, predicate);
|
||||
}
|
||||
|
||||
export function matchCodePointString(
|
||||
cursor: SourceCursor,
|
||||
pattern: CodePointString,
|
||||
): TextMatch {
|
||||
const start = cursor.checkpoint();
|
||||
|
||||
for (const expected of pattern.codePoints) {
|
||||
if (cursor.peek() !== expected) {
|
||||
cursor.restore(start);
|
||||
return TextMatch.none();
|
||||
}
|
||||
cursor.advance();
|
||||
}
|
||||
|
||||
const span = cursor.spanFrom(start);
|
||||
return TextMatch.match(span, cursor.slice(span));
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue