Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
oleiade committed Dec 8, 2023
2 parents 918b7c9 + 68e9015 commit 0c981b3
Show file tree
Hide file tree
Showing 13 changed files with 1,452 additions and 611 deletions.
243 changes: 178 additions & 65 deletions README.md

Large diffs are not rendered by default.

15 changes: 11 additions & 4 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@

- [ ] Create `Bytes` interface type for bytes file's content
- [ ] Create `String` or `Characters` interface type for characters file's content
- [ ] Add Examples
- [ ] Document Recognize as explicitly as possible
- [ ] Add an `ErrInfiniteLoop` (`Many0`)
- [ ] Sort Out Fatal/Non-Fatal errors (distinguish whether a parser failed in an expected manner, or if the whole parsing should be interrupted)
- [ ] Reduce Int8/Int64 allocations (their parsers could be somewhat simplified?)
- [ ] Add combinator to parse whitespace (+ helper for multispace0/1?)
- [ ] Refactor TakeWhileOneOf to be "just" TakeWhile
- [ ] Refactor space to be of the form space0 and space1
- [ ] Rename `LF` to `Newline`
- [X] Document Recognize as explicitly as possible
- [X] Add Examples
- [x] Add Benchmarks
- [x] Make sure the Failure messages are properly cased
- [x] Rename `p` parser arguments to `parse` for clearer code
Expand All @@ -20,9 +23,13 @@
- [ ] Rename `Preceded` to `Prefixed`
- [ ] Rename `Terminated` to `Suffixed`
- [ ] Rename `Sequence` to `List`?
- [ ] Introduce `SeparatedList` as a result of previous?
- [ ] Rename `Satisfy` to `Satisfies`?
- [X] Introduce `SeparatedList` as a result of previous?
- [X] Create `bytes.go` file to distinguish from characters

## Track

- [ ] Chase allocations, document them, and reduce their amount as much as possible

## NoNos
- [X] Add an `ErrInfiniteLoop` (`Many0`)
99 changes: 99 additions & 0 deletions bytes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package gomme

import (
"fmt"
"strings"
)

// Take returns a subset of the input of size `count`.
func Take[I Bytes](count uint) Parser[I, I] {
return func(input I) Result[I, I] {
if len(input) == 0 && count > 0 {
return Failure[I, I](NewError(input, "TakeUntil"), input)
}

if uint(len(input)) < count {
return Failure[I, I](NewError(input, "Take"), input)
}

return Success(input[:count], input[count:])
}
}

// TakeUntil parses any number of characters until the provided parser is successful.
// If the provided parser is not successful, the parser fails, and the entire input is
// returned as the Result's Remaining.
func TakeUntil[I Bytes, O any](parse Parser[I, O]) Parser[I, I] {
return func(input I) Result[I, I] {
if len(input) == 0 {
return Failure[I, I](NewError(input, "TakeUntil"), input)
}

pos := 0
for ; pos < len(input); pos++ {
current := input[pos:]
res := parse(current)
if res.Err == nil {
return Success(input[:pos], input[pos:])
}

continue
}

return Failure[I, I](NewError(input, "TakeUntil"), input)
}
}

// TakeWhileMN returns the longest input subset that matches the predicates, within
// the boundaries of `atLeast` <= len(input) <= `atMost`.
//
// If the provided parser is not successful or the pattern is out of the
// `atLeast` <= len(input) <= `atMost` range, the parser fails, and the entire
// input is returned as the Result's Remaining.
func TakeWhileMN[I Bytes](atLeast, atMost uint, predicate func(rune) bool) Parser[I, I] {
return func(input I) Result[I, I] {
if len(input) == 0 {
return Failure[I, I](NewError(input, "TakeWhileMN"), input)
}

// Input is shorter than the minimum expected matching length,
// it is thus not possible to match it within the established
// constraints.
if uint(len(input)) < atLeast {
return Failure[I, I](NewError(input, "TakeWhileMN"), input)
}

lastValidPos := 0
for idx := 0; idx < len(input); idx++ {
if uint(idx) == atMost {
break
}

matched := predicate(rune(input[idx]))
if !matched {
if uint(idx) < atLeast {
return Failure[I, I](NewError(input, "TakeWhileMN"), input)
}

return Success(input[:idx], input[idx:])
}

lastValidPos++
}

return Success(input[:lastValidPos], input[lastValidPos:])
}
}

// Token parses a token from the input, and returns the part of the input that
// matched the token.
// If the token could not be found, the parser returns an error result.
func Token[I Bytes](token string) Parser[I, I] {
return func(input I) Result[I, I] {
if !strings.HasPrefix(string(input), token) {
return Failure[I, I](NewError(input, fmt.Sprintf("Token(%s)", token)), input)
}

return Success(input[:len(token)], input[len(token):])
}
}
Loading

0 comments on commit 0c981b3

Please sign in to comment.