Skip to content

Commit

Permalink
feat(combinators/*Until): add takeUntil and skipUntil combinators
Browse files Browse the repository at this point in the history
  • Loading branch information
norskeld committed Jul 12, 2022
1 parent 63e3166 commit 003f82d
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/combinators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export * from './combinators/optional'
export * from './combinators/sepBy'
export * from './combinators/sequence'
export * from './combinators/take'
export * from './combinators/until'
76 changes: 76 additions & 0 deletions src/combinators/until.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { type Parser } from '../state'

export function takeUntil<T, S>(parser: Parser<T>, terminator: Parser<S>): Parser<[Array<T>, S]> {
return {
parse(input, pos) {
const values: Array<T> = []
let nextPos = pos

while (true) {
const resultT = terminator.parse(input, nextPos)

switch (resultT.isOk) {
// If ok, then we stumbled upon a terminating parser, so push final matches, and then
// return accumulated values.
case true: {
return {
isOk: true,
pos: resultT.pos,
value: [values, resultT.value]
}
}

// Otherwise try to run source parser and push results into `values`.
// If it fails, then return early and stop parsing.
case false: {
const resultP = parser.parse(input, nextPos)

if (resultP.isOk) {
values.push(resultP.value)
nextPos = resultP.pos
continue
}

return resultP
}
}
}
}
}
}

export function skipUntil<T, S>(parser: Parser<T>, terminator: Parser<S>): Parser<S> {
return {
parse(input, pos) {
let nextPos = pos

while (true) {
const resultT = terminator.parse(input, nextPos)

switch (resultT.isOk) {
// If ok, then we stumbled upon a terminating parser, so return its value.
case true: {
return {
isOk: true,
pos: resultT.pos,
value: resultT.value
}
}

// Otherwise try to run source parser *ignoring* its results.
// If it fails, then return early and stop parsing.
case false: {
const resultP = parser.parse(input, nextPos)

if (resultP.isOk) {
nextPos = resultP.pos
continue
}

return resultP
}
}
}
}
}
}

0 comments on commit 003f82d

Please sign in to comment.