chomp

package module
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 25, 2026 License: MIT Imports: 4 Imported by: 2

README ΒΆ

Chomp

Nix Go MIT

A parser combinator library for Go that makes parsing text intuitive and maintainable. Stop wrestling with regex and start writing parsers that read like natural grammar.

Inspired by nom πŸ’œ.

Why Chomp?

Parser combinators offer significant advantages over regular expressions:

Chomp Regex
Readability Reads like grammar rules Often "write-only" patterns
Composability Build complex parsers from simple, reusable pieces Monolithic patterns that resist reuse
Error Messages Clear context on what failed and where Generic "no match" or cryptic positions
Maintainability Easy to modify and extend Small changes can break everything
Nested Structures Natural support for recursion Struggles or impossible
Type Safety Compile-time guarantees Runtime string manipulation

Installation

go get github.com/purpleclay/chomp

How It Works

At the heart of chomp is the combinator - a function that attempts to parse text and returns a tuple (rem, ext, err):

                       input
                         β”‚
                         β–Ό
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚     Combinator      β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                         β”‚
          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
          β–Ό              β–Ό              β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚    rem    β”‚  β”‚    ext    β”‚  β”‚    err    β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
      remaining      extracted    error (if any)
        text           text
// Parse a simple tag
rem, ext, _ := chomp.Tag("Hello")("Hello, World!")
// ext: "Hello"
// rem: ", World!"

Combinators can be composed together to build sophisticated parsers:

// Parse a key-value pair like "name=alice"
func KeyValue() chomp.Combinator[[]string] {
    return chomp.SepPair(
        chomp.While(chomp.IsLetter),  // key: letters
        chomp.Tag("="),               // separator (discarded)
        chomp.While(chomp.IsLetter),  // value: letters
    )
}

rem, kv, _ := KeyValue()("name=alice&age=30")
// kv: ["name", "alice"]
// rem: "&age=30"

Examples

Real-world parser examples:

Documentation

Documentation ΒΆ

Overview ΒΆ

Package chomp provides a parser combinator library for chomping strings (a byte at a time) in Go. A more intuitive way to parse text without having to write a single regex

Index ΒΆ

Constants ΒΆ

This section is empty.

Variables ΒΆ

View Source
var (
	// IsDigit determines whether a rune is a decimal digit. A rune is classed
	// as a digit if it is between the ASCII range of '0' or '9', or if it belongs
	// within the Unicode [Nd] category.
	//
	// [Nd]: https://www.fileformat.info/info/unicode/category/Nd/list.htm
	IsDigit = isDigit{}

	// IsLetter determines if a rune is a letter. A rune is classed as a letter
	// if it is between the ASCII range of 'a' and 'z' (including its uppercase
	// equivalents), or it belongs within any of the Unicode letter categories:
	// [Lu] [LI] [Lt] [Lm] [Lo].
	//
	// [Lu]: https://www.fileformat.info/info/unicode/category/Lu/list.htm
	// [LI]: https://www.fileformat.info/info/unicode/category/Ll/list.htm
	// [Lt]: https://www.fileformat.info/info/unicode/category/Lt/list.htm
	// [Lm]: https://www.fileformat.info/info/unicode/category/Lm/list.htm
	// [Lo]: https://www.fileformat.info/info/unicode/category/Lo/list.htm
	IsLetter = isLetter{}

	// IsAlphanumeric determines whether a rune is a decimal digit or a letter.
	// This convenience method wraps the existing [IsDigit] and [IsLetter]
	// predicates.
	IsAlphanumeric = isAlphanumeric{}

	// IsLineEnding determines whether a rune is one of the following ASCII
	// line ending characters '\r' or '\n'.
	IsLineEnding = isLineEnding{}

	// IsSpace determines whether a rune is a space character. A rune is classed
	// as a space if it is either a space ' ' or a tab '\t'.
	IsSpace = isSpace{}

	// IsMultispace determines whether a rune is a whitespace character. A rune
	// is classed as whitespace if it is a space ' ', tab '\t', newline '\n',
	// or carriage return '\r'.
	IsMultispace = isMultispace{}

	// IsHexDigit determines whether a rune is a hexadecimal digit. A rune is
	// classed as a hex digit if it is between '0'-'9', 'a'-'f', or 'A'-'F'.
	IsHexDigit = isHexDigit{}

	// IsOctalDigit determines whether a rune is an octal digit. A rune is classed
	// as an octal digit if it is between '0' and '7'.
	IsOctalDigit = isOctalDigit{}

	// IsBinaryDigit determines whether a rune is a binary digit. A rune is classed
	// as a binary digit if it is either '0' or '1'.
	IsBinaryDigit = isBinaryDigit{}
)

Functions ΒΆ

This section is empty.

Types ΒΆ

type Combinator ΒΆ

type Combinator[T Result] func(string) (string, T, error)

Combinator is a higher-order function capable of parsing text under a defined condition. Combinators can be combined to form more complex parsers. Upon success, a combinator will return both the unparsed and parsed text. All combinators are strict and must parse its input. Any failure to do so should raise a CombinatorParseError.

func All ΒΆ

func All[T Result](c ...Combinator[T]) Combinator[[]string]

All will match the input text against a series of [Combinator]s. All combinators must match in the order provided.

chomp.All(
	chomp.Tag("Hello"),
	chomp.Until("W"),
	chomp.Tag("World!"))("Hello, World!")
// ("", []string{"Hello", ", ", "World!"}, nil)

func AllConsuming ΒΆ added in v0.6.0

func AllConsuming[T Result](c Combinator[T]) Combinator[T]

AllConsuming ensures the entire input is consumed by the inner parser, failing if any text remains unparsed.

chomp.AllConsuming(chomp.Tag("Hello"))("Hello")
// ("", "Hello", nil)

chomp.AllConsuming(chomp.Tag("Hello"))("Hello, World!")
// ("Hello, World!", "", error)

func Alpha ΒΆ added in v0.5.0

func Alpha() Combinator[string]

Alpha matches one or more ASCII or Unicode letters. Equivalent to While(IsLetter).

chomp.Alpha()("Hello123")
// ("123", "Hello", nil)

func Alpha0 ΒΆ added in v0.5.0

func Alpha0() Combinator[string]

Alpha0 matches zero or more ASCII or Unicode letters. Equivalent to WhileN(IsLetter, 0).

chomp.Alpha0()("123Hello")
// ("123Hello", "", nil)

func Alphanumeric ΒΆ added in v0.5.0

func Alphanumeric() Combinator[string]

Alphanumeric matches one or more alphanumeric characters. Equivalent to While(IsAlphanumeric).

chomp.Alphanumeric()("Hello123!")
// ("!", "Hello123", nil)

func Alphanumeric0 ΒΆ added in v0.5.0

func Alphanumeric0() Combinator[string]

Alphanumeric0 matches zero or more alphanumeric characters. Equivalent to WhileN(IsAlphanumeric, 0).

chomp.Alphanumeric0()("!Hello123")
// ("!Hello123", "", nil)

func Any ΒΆ

func Any(str string) Combinator[string]

Any must match at least one character from the provided sequence at the beginning of the input text. Parsing stops upon the first unmatched character.

chomp.Any("eH")("Hello, World!")
// ("llo, World!", "He", nil)

func AnyAlphanumeric ΒΆ added in v0.6.0

func AnyAlphanumeric() Combinator[string]

AnyAlphanumeric matches a single alphanumeric character.

chomp.AnyAlphanumeric()("a1!")
// ("1!", "a", nil)

func AnyBinaryDigit ΒΆ added in v0.6.0

func AnyBinaryDigit() Combinator[string]

AnyBinaryDigit matches a single binary digit (0-1).

chomp.AnyBinaryDigit()("101")
// ("01", "1", nil)

func AnyChar ΒΆ added in v0.5.0

func AnyChar() Combinator[string]

AnyChar matches any single character at the beginning of the input text.

chomp.AnyChar()("Hello")
// ("ello", "H", nil)

func AnyDigit ΒΆ added in v0.6.0

func AnyDigit() Combinator[string]

AnyDigit matches a single decimal digit (0-9).

chomp.AnyDigit()("123")
// ("23", "1", nil)

func AnyHexDigit ΒΆ added in v0.6.0

func AnyHexDigit() Combinator[string]

AnyHexDigit matches a single hexadecimal digit (0-9, a-f, A-F).

chomp.AnyHexDigit()("fF0")
// ("F0", "f", nil)

func AnyLetter ΒΆ added in v0.6.0

func AnyLetter() Combinator[string]

AnyLetter matches a single ASCII or Unicode letter.

chomp.AnyLetter()("Hello")
// ("ello", "H", nil)

func AnyOctalDigit ΒΆ added in v0.6.0

func AnyOctalDigit() Combinator[string]

AnyOctalDigit matches a single octal digit (0-7).

chomp.AnyOctalDigit()("752")
// ("52", "7", nil)

func BinaryDigit ΒΆ added in v0.5.0

func BinaryDigit() Combinator[string]

BinaryDigit matches one or more binary digits (0-1). Equivalent to While(IsBinaryDigit).

chomp.BinaryDigit()("1010 rest")
// (" rest", "1010", nil)

func BinaryDigit0 ΒΆ added in v0.5.0

func BinaryDigit0() Combinator[string]

BinaryDigit0 matches zero or more binary digits (0-1). Equivalent to WhileN(IsBinaryDigit, 0).

chomp.BinaryDigit0()("234")
// ("234", "", nil)

func BracketAngled ΒΆ

func BracketAngled() Combinator[string]

BracketAngled will match any text delimited (or surrounded) by a pair of <angled brackets>.

chomp.BracketAngled()("<Hello, World!>")
// ("", "Hello, World!", nil)

func BracketSquare ΒΆ

func BracketSquare() Combinator[string]

BracketSquare will match any text delimited (or surrounded) by a pair of [square brackets].

chomp.BracketSquare()("[Hello, World!]")
// ("", "Hello, World!", nil)

func Char ΒΆ added in v0.5.0

func Char(c rune) Combinator[string]

Char matches a specific single character at the beginning of the input text.

chomp.Char(',')(",,rest")
// (",rest", ",", nil)

func Cond ΒΆ added in v0.6.0

func Cond[T Result](cond bool, c Combinator[T]) Combinator[T]

Cond conditionally applies a parser based on a boolean flag. If the condition is true, the parser is applied. Otherwise, it returns an empty result without consuming input. Enables optional parsing logic.

chomp.Cond(true, chomp.Tag("Hello"))("Hello, World!")
// (", World!", "Hello", nil)

chomp.Cond(false, chomp.Tag("Hello"))("Hello, World!")
// ("Hello, World!", "", nil)

func Consumed ΒΆ added in v0.6.0

func Consumed[T Result](c Combinator[T]) Combinator[[]string]

Consumed provides both the raw consumed text and the parsed output as a tuple. Enables access to both representations simultaneously.

chomp.Consumed(chomp.SepPair(
    chomp.Alpha(),
    chomp.Tag(", "),
    chomp.Alpha()))("Hello, World!")
// ("!", []string{"Hello, World", "Hello", "World"}, nil)

func Crlf ΒΆ

func Crlf() Combinator[string]

Crlf must match either a CR '\r' or CRLF '\r\n' line ending.

chomp.Crlf()("\r\nHello")
// ("Hello", "\r\n", nil)

func Cut ΒΆ added in v0.6.0

func Cut[T Result](c Combinator[T]) Combinator[T]

Cut converts recoverable parsing errors into fatal failures, preventing backtracking past decision points. Improves error messaging by committing to a parsing path once the cut point is reached.

// Without Cut, First would try the second alternative
// With Cut, once "if" matches, failure is fatal
chomp.First(
    chomp.All(
        chomp.Tag("if"),
        chomp.Cut(chomp.Tag("("))),
    chomp.Tag("identifier"))("if x")
// ("if x", nil, CutError{...})

func Delimited ΒΆ

func Delimited[T, U, V Result](left Combinator[T], str Combinator[U], right Combinator[V]) Combinator[U]

Delimited will match a series of combinators against the input text. All must match, with the delimiters being discarded.

chomp.Delimited(
	chomp.Tag("'"),
	chomp.Tag("Hello, World!"),
	chomp.Tag("'"))("'Hello, World!'")
// ("", "Hello, World!", nil)

func Digit ΒΆ added in v0.5.0

func Digit() Combinator[string]

Digit matches one or more decimal digits. Equivalent to While(IsDigit).

chomp.Digit()("123abc")
// ("abc", "123", nil)

func Digit0 ΒΆ added in v0.5.0

func Digit0() Combinator[string]

Digit0 matches zero or more decimal digits. Equivalent to WhileN(IsDigit, 0).

chomp.Digit0()("abc123")
// ("abc123", "", nil)

func Eof ΒΆ added in v0.6.0

func Eof() Combinator[string]

Eof matches only when at the end of input, returning an empty string on success. Prevents partial parsing by ensuring no input remains.

chomp.Eof()("")
// ("", "", nil)

chomp.Eof()("remaining")
// ("remaining", "", error)

func Eol ΒΆ added in v0.3.0

func Eol() Combinator[string]

Eol will scan and return any text before any ASCII line ending characters. Line endings are discarded.

chomp.Eol()(`Hello, World!\nIt's a great day!`)
// ("It's a great day!", "Hello, World!", nil)

func Escaped ΒΆ added in v0.5.0

func Escaped(normal Combinator[string], escape rune, escapable Combinator[string]) Combinator[string]

Escaped parses a string containing escape sequences. It takes a normal content combinator, an escape character, and a combinator that matches valid characters after the escape. The escape sequences are preserved in the output as-is.

chomp.Escaped(chomp.While(chomp.IsLetter), '\\', chomp.OneOf(`"n\`))(`Hello\"World`)
// ("", `Hello\"World`, nil)

func EscapedTransform ΒΆ added in v0.5.0

func EscapedTransform(normal Combinator[string], escape rune, transform Combinator[string]) Combinator[string]

EscapedTransform parses a string containing escape sequences and transforms them. It takes a normal content combinator, an escape character, and a transform function that converts escape sequences to their actual values.

transform := func(s string) (string, string, error) {
    switch s[0] {
    case 'n':
        return s[1:], "\n", nil
    case '"':
        return s[1:], "\"", nil
    case '\\':
        return s[1:], "\\", nil
    }
    return s, "", errors.New("invalid escape")
}
chomp.EscapedTransform(chomp.While(chomp.IsLetter), '\\', transform)(`Hello\nWorld`)
// ("", "Hello\nWorld", nil)

func Fill ΒΆ added in v0.6.0

func Fill[T Result](c Combinator[T], n uint) Combinator[[]string]

Fill will scan the input text and match the Combinator exactly n times, populating the result slice. All n matches must succeed.

chomp.Fill(chomp.Alpha(), 3)("abcdef")
// ("def", []string{"a", "b", "c"}, nil)

func First ΒΆ

func First[T Result](c ...Combinator[T]) Combinator[T]

First will match the input text against a series of [Combinator]s. Matching stops as soon as the first combinator succeeds. One Combinator must match. For better performance, try and order the combinators from most to least likely to match.

If a CutError is encountered during parsing, backtracking stops immediately and the error is propagated. This allows Cut to commit to a parsing path.

chomp.First(
	chomp.Tag("Good Morning"),
	chomp.Tag("Hello"))("Good Morning, World!")
// (" ,World!", "Good Morning", nil)

func Flatten ΒΆ added in v0.4.0

func Flatten(c Combinator[[]string]) Combinator[string]

Flatten the output from a Combinator by joining all extracted values into a string.

chomp.Flatten(
	chomp.Many(chomp.Parentheses()),
)("(H)(el)(lo), World!")
// (", World!", "Hello", nil)

func HexDigit ΒΆ added in v0.5.0

func HexDigit() Combinator[string]

HexDigit matches one or more hexadecimal digits (0-9, a-f, A-F). Equivalent to While(IsHexDigit).

chomp.HexDigit()("1a2B3c rest")
// (" rest", "1a2B3c", nil)

func HexDigit0 ΒΆ added in v0.5.0

func HexDigit0() Combinator[string]

HexDigit0 matches zero or more hexadecimal digits (0-9, a-f, A-F). Equivalent to WhileN(IsHexDigit, 0).

chomp.HexDigit0()("xyz")
// ("xyz", "", nil)

func I ΒΆ

I extracts and returns a single string from the result of the inner Combinator. Combinators of differing return types can be successfully chained together while using this conversion combinator.

chomp.I(chomp.SepPair(
	chomp.Tag("Hello"),
	chomp.Tag(", "),
	chomp.Tag("World")), 1)("Hello, World!")
// ("!", "World", nil)

func LengthCount ΒΆ added in v0.6.0

func LengthCount[T Result](length MappedCombinator[uint, string], c Combinator[T]) Combinator[[]string]

LengthCount will first parse a length value using the length combinator, then apply the element combinator that exact number of times.

chomp.LengthCount(
    chomp.Map(chomp.Digit(), func(s string) uint {
        n, _ := strconv.ParseUint(s, 10, 64)
        return uint(n)
    }),
    chomp.Alpha(),
)("3abc")
// ("", []string{"a", "b", "c"}, nil)

func Many ΒΆ added in v0.2.0

func Many[T Result](c Combinator[T]) Combinator[[]string]

Many will scan the input text, and it must match the Combinator at least once. This Combinator is greedy and will continuously execute until the first failed match. It is the equivalent of calling ManyN with an argument of 1.

chomp.Many(one.Of("Ho"))("Hello, World!")
// ("ello, World!", []string{"H"}, nil)

func ManyN ΒΆ added in v0.2.0

func ManyN[T Result](c Combinator[T], n uint) Combinator[[]string]

ManyN will scan the input text and match the Combinator a minimum number of times. This Combinator is greedy and will continuously execute until the first failed match.

chomp.ManyN(chomp.OneOf("W"), 0)("Hello, World!")
// ("Hello, World!", nil, nil)

func ManyTill ΒΆ added in v0.6.0

func ManyTill[T, U Result](c Combinator[T], term Combinator[U]) Combinator[[]string]

ManyTill will scan the input text, matching the Combinator repeatedly until the terminator matches. The terminator is consumed but not included in the result. At least one element must match before the terminator.

chomp.ManyTill(chomp.AnyChar(), chomp.Tag("END"))("abcEND")
// ("", []string{"a", "b", "c"}, nil)

func ManyTill0 ΒΆ added in v0.6.0

func ManyTill0[T, U Result](c Combinator[T], term Combinator[U]) Combinator[[]string]

ManyTill0 will scan the input text, matching the Combinator repeatedly until the terminator matches. The terminator is consumed but not included in the result. Zero or more elements may match before the terminator.

chomp.ManyTill0(chomp.AnyChar(), chomp.Tag("END"))("END")
// ("", []string{}, nil)

func Multispace ΒΆ added in v0.5.0

func Multispace() Combinator[string]

Multispace matches one or more whitespace characters (space, tab, newline, carriage return). Equivalent to While(IsMultispace).

chomp.Multispace()("  \n\tHello")
// ("Hello", "  \n\t", nil)

func Multispace0 ΒΆ added in v0.5.0

func Multispace0() Combinator[string]

Multispace0 matches zero or more whitespace characters (space, tab, newline, carriage return). Equivalent to WhileN(IsMultispace, 0).

chomp.Multispace0()("Hello")
// ("Hello", "", nil)

func Newline ΒΆ added in v0.5.0

func Newline() Combinator[string]

Newline matches a single newline character '\n'.

chomp.Newline()("\nHello")
// ("Hello", "\n", nil)

func NoneOf ΒΆ

func NoneOf(str string) Combinator[string]

NoneOf must not match a single character at the beginning of the text from the provided sequence.

chomp.NoneOf("loWrd!e")("Hello, World!")
// ("ello, World!", "H", nil)

func Not ΒΆ

func Not(str string) Combinator[string]

Not must not match at least one character at the beginning of the input text from the provided sequence. Parsing stops upon the first matched character.

chomp.Not("ol")("Hello, World!")
// ("llo, World!", "He", nil)

func NotLineEnding ΒΆ added in v0.5.0

func NotLineEnding() Combinator[string]

NotLineEnding matches any characters until a line ending ('\n' or '\r'). Requires at least one character to be matched.

chomp.NotLineEnding()("Hello, World!\nNext line")
// ("\nNext line", "Hello, World!", nil)

func OctalDigit ΒΆ added in v0.5.0

func OctalDigit() Combinator[string]

OctalDigit matches one or more octal digits (0-7). Equivalent to While(IsOctalDigit).

chomp.OctalDigit()("0127 rest")
// (" rest", "0127", nil)

func OctalDigit0 ΒΆ added in v0.5.0

func OctalDigit0() Combinator[string]

OctalDigit0 matches zero or more octal digits (0-7). Equivalent to WhileN(IsOctalDigit, 0).

chomp.OctalDigit0()("89")
// ("89", "", nil)

func OneOf ΒΆ

func OneOf(str string) Combinator[string]

OneOf must match a single character at the beginning of the text from the provided sequence.

chomp.OneOf("!,eH")("Hello, World!")
// ("ello, World!", "H", nil)

func Opt ΒΆ

func Opt[T Result](c Combinator[T]) Combinator[T]

Opt allows a Combinator to be optional by discarding its returned error and not modifying the input text upon failure.

chomp.Opt(chomp.Tag("Hey"))("Hello, World!")
// ("Hello, World!", "", nil)

func Pair ΒΆ

func Pair[T, U Result](c1 Combinator[T], c2 Combinator[U]) Combinator[[]string]

Pair will scan the input text and match each Combinator in turn. Both combinators must match.

chomp.Pair(chomp.Tag("Hello,"), chomp.Tag(" World"))("Hello, World!")
// ("!", []string{"Hello,", " World"}, nil)

func Parentheses ΒΆ

func Parentheses() Combinator[string]

Parentheses will match any text delimited (or surrounded) by a pair of (parentheses).

chomp.Parentheses()("(Hello, World!)")
// ("", "Hello, World!", nil)

func Peek ΒΆ added in v0.3.0

func Peek[T Result](c Combinator[T]) Combinator[T]

Peek will scan the text and apply the Combinator without consuming any input. Useful if you need to look ahead.

chomp.Peek(chomp.Tag("Hello"))("Hello, World!")
// ("Hello, World!", "Hello", nil)

chomp.Peek(
	chomp.Many(chomp.Suffixed(chomp.Tag(" "), chomp.Until(" "))),
)("Hello and Good Morning!")
// ("Hello and Good Morning!", []string{"Hello", "and", "Good"}, nil)

func PeekNot ΒΆ added in v0.6.0

func PeekNot[T Result](c Combinator[T]) Combinator[string]

PeekNot succeeds when the inner parser fails without consuming input. Implements negative lookahead for validation. On success, returns an empty string without consuming any input. Pairs with Peek for positive lookahead.

chomp.PeekNot(chomp.Tag("Hello"))("World!")
// ("World!", "", nil)

chomp.PeekNot(chomp.Tag("Hello"))("Hello, World!")
// ("Hello, World!", "", error)

func Prefixed ΒΆ added in v0.2.0

func Prefixed(c, pre Combinator[string]) Combinator[string]

Prefixed will scan the input text for a defined prefix and discard it before matching the remaining text against the Combinator. Both combinators must match.

chomp.Prefixed(
	chomp.Tag("Hello"),
	chomp.Tag(`"`))(`"Hello, World!"`)
// (`, World!"`, "Hello", nil)

func QuoteDouble ΒΆ

func QuoteDouble() Combinator[string]

QuoteDouble will match any text delimited (or surrounded) by a pair of "double quotes".

chomp.DoubleQuote()(`"Hello, World!"`)
// ("", "Hello, World!", nil)

func QuoteSingle ΒΆ

func QuoteSingle() Combinator[string]

QuoteSingle will match any text delimited (or surrounded) by a pair of 'single quotes'.

chomp.QuoteSingle()("'Hello, World!'")
// ("", "Hello, World!", nil)

func Recognize ΒΆ added in v0.6.0

func Recognize[T Result](c Combinator[T]) Combinator[string]

Recognize returns the consumed input as the output, regardless of the inner parser's result. Useful for capturing complex patterns as text.

chomp.Recognize(chomp.SepPair(
    chomp.Alpha(),
    chomp.Tag(", "),
    chomp.Alpha()))("Hello, World!")
// ("!", "Hello, World", nil)

func Repeat ΒΆ

func Repeat[T Result](c Combinator[T], n uint) Combinator[[]string]

Repeat will scan the input text and match the combinator the defined number of times. Every execution must match.

chomp.Repeat(chomp.Parentheses(), 2)("(Hello)(World)(!)")
// ("(!)", []string{"(Hello)", "(World)"}, nil)

func RepeatRange ΒΆ added in v0.2.0

func RepeatRange[T Result](c Combinator[T], n, m uint) Combinator[[]string]

RepeatRange will scan the input text and match the Combinator between a minimum and maximum number of times. It must match the expected minimum number of times.

chomp.RepeatRange(chomp.OneOf("Hleo"), 1, 8)("Hello, World!")
// (", World!", []string{"H", "e", "l", "l", "o"}, nil)

func Rest ΒΆ added in v0.6.0

func Rest() Combinator[string]

Rest returns all remaining unconsumed input as a string value. Always succeeds, even with empty input.

chomp.Rest()("Hello, World!")
// ("", "Hello, World!", nil)

chomp.Rest()("")
// ("", "", nil)

func S ΒΆ

S wraps the result of the inner Combinator within a string slice. Combinators of differing return types can be successfully chained together while using this conversion combinator.

chomp.S(chomp.Until(","))("Hello, World!")
// (", World!", []string{"Hello"}, nil)

func Satisfy ΒΆ added in v0.5.0

func Satisfy(pred func(rune) bool) Combinator[string]

Satisfy matches a single character at the beginning of the input text that satisfies the given predicate function.

chomp.Satisfy(func(r rune) bool { return r >= 'A' && r <= 'Z' })("Hello")
// ("ello", "H", nil)

func SepPair ΒΆ

func SepPair[T, U, V Result](c1 Combinator[T], sep Combinator[U], c2 Combinator[V]) Combinator[[]string]

SepPair will scan the input text and match each Combinator, discarding the separator's output. All combinators must match.

chomp.SepPair(
	chomp.Tag("Hello"),
	chomp.Tag(", "),
	chomp.Tag("World"))("Hello, World!")
// ("!", []string{"Hello", "World"}, nil)

func SeparatedList ΒΆ added in v0.6.0

func SeparatedList[T, U Result](c Combinator[T], sep Combinator[U]) Combinator[[]string]

SeparatedList will scan the input text and match the Combinator separated by the provided separator. At least one element must match. The separator output is discarded.

chomp.SeparatedList(chomp.Alpha(), chomp.Tag(","))("a,b,c,")
// (",", []string{"a", "b", "c"}, nil)

func SeparatedList0 ΒΆ added in v0.6.0

func SeparatedList0[T, U Result](c Combinator[T], sep Combinator[U]) Combinator[[]string]

SeparatedList0 will scan the input text and match the Combinator separated by the provided separator. Zero or more elements may match. The separator output is discarded.

chomp.SeparatedList0(chomp.Alpha(), chomp.Tag(","))("123")
// ("123", []string{}, nil)

func Space ΒΆ added in v0.5.0

func Space() Combinator[string]

Space matches one or more space or tab characters. Equivalent to While(IsSpace).

chomp.Space()("   Hello")
// ("Hello", "   ", nil)

func Space0 ΒΆ added in v0.5.0

func Space0() Combinator[string]

Space0 matches zero or more space or tab characters. Equivalent to WhileN(IsSpace, 0).

chomp.Space0()("Hello")
// ("Hello", "", nil)

func Suffixed ΒΆ added in v0.2.0

func Suffixed(c, suf Combinator[string]) Combinator[string]

Suffixed will scan the input text against the Combinator before matching a suffix and discarding it. Both combinators must match.

chomp.Suffixed(
	chomp.Tag("Hello"),
	chomp.Tag(", "))("Hello, World!")
// ("World!", "Hello", nil)

func Tab ΒΆ added in v0.5.0

func Tab() Combinator[string]

Tab matches a single tab character '\t'.

chomp.Tab()("\tHello")
// ("Hello", "\t", nil)

func Tag ΒΆ

func Tag(str string) Combinator[string]

Tag must match a series of characters at the beginning of the input text in the exact order and case provided.

chomp.Tag("Hello")("Hello, World!")
// (", World!", "Hello", nil)

func TagNoCase ΒΆ added in v0.5.0

func TagNoCase(str string) Combinator[string]

TagNoCase must match a series of characters at the beginning of the input text in the exact order provided, but ignoring case. The matched text from the input is returned (preserving the original casing).

chomp.TagNoCase("hello")("HELLO, World!")
// (", World!", "HELLO", nil)

func Take ΒΆ added in v0.5.0

func Take(n uint) Combinator[string]

Take will consume exactly n characters from the beginning of the input text. Unicode characters are handled correctly by counting runes, not bytes.

chomp.Take(5)("Hello, World!")
// (", World!", "Hello", nil)

func TakeUntil1 ΒΆ added in v0.5.0

func TakeUntil1(str string) Combinator[string]

TakeUntil1 will scan the input text for the first occurrence of the provided series of characters, requiring at least one character to be matched before the delimiter. Everything until that point in the text will be matched.

chomp.TakeUntil1(",")("Hello, World!")
// (", World!", "Hello", nil)

chomp.TakeUntil1(",")(",World!")
// Error: must match at least one character

func Until ΒΆ

func Until(str string) Combinator[string]

Until will scan the input text for the first occurrence of the provided series of characters. Everything until that point in the text will be matched.

chomp.Until("World")("Hello, World!")
// ("World!", "Hello, ", nil)

func Verify ΒΆ added in v0.6.0

func Verify[T Result](c Combinator[T], predicate func(T) bool) Combinator[T]

Verify validates the parsed result against a predicate function without modifying the output. If the predicate returns false, the combinator fails. Useful for semantic validation of parsed data.

chomp.Verify(chomp.Alpha(), func(s string) bool {
    return len(s) >= 3
})("Hello, World!")
// (", World!", "Hello", nil)

chomp.Verify(chomp.Alpha(), func(s string) bool {
    return len(s) >= 10
})("Hello, World!")
// ("Hello, World!", "", error)

func While ΒΆ

func While(p Predicate) Combinator[string]

While will scan the input text, testing each character against the provided Predicate. The Predicate must match at least one character.

chomp.While(chomp.IsLetter)("Hello, World!")
// (", World!", "Hello", nil)

func WhileN ΒΆ added in v0.3.0

func WhileN(p Predicate, n uint) Combinator[string]

WhileN will scan the input text, testing each character against the provided Predicate. The Predicate must match at least n characters. If n is zero, this becomes an optional combinator.

chomp.WhileN(chomp.IsLetter, 1)("Hello, World!")
// (", World!", "Hello", nil)

chomp.WhileN(chomp.IsDigit, 0)("Hello, World!")
// ("Hello, World!", "", nil)

func WhileNM ΒΆ added in v0.3.0

func WhileNM(p Predicate, n, m uint) Combinator[string]

WhileNM will scan the input text, testing each character against the provided Predicate. The Predicate must match a minimum of n and upto a maximum of m characters. If n is zero, this becomes an optional combinator.

chomp.WhileNM(chomp.IsLetter, 1, 8)("Hello, World!")
// (", World!", "Hello", nil)

func WhileNot ΒΆ

func WhileNot(p Predicate) Combinator[string]

WhileNot will scan the input text, testing each character against the provided Predicate. The Predicate must not match at least one character. It has the inverse behavior of While.

chomp.WhileNot(chomp.IsDigit)("Hello, World!")
// ("", "Hello, World!", nil)

func WhileNotN ΒΆ added in v0.3.0

func WhileNotN(p Predicate, n uint) Combinator[string]

WhileNotN will scan the input text, testing each character against the provided Predicate. The Predicate must not match at least n characters. If n is zero, this becomes an optional combinator. It has the inverse behavior of WhileN.

chomp.WhileNotN(chomp.IsDigit, 1)("Hello, World!")
// ("", "Hello, World!", nil)

chomp.WhileNotN(chomp.IsLetter, 0)("Hello, World!")
// ("Hello, World!", "", nil)

func WhileNotNM ΒΆ added in v0.3.0

func WhileNotNM(p Predicate, n, m uint) Combinator[string]

WhileNotNM will scan the input text, testing each character against the provided Predicate. The Predicate must not match a minimum of n and upto a maximum of m characters. If n is zero, this becomes an optional combinator. It has the inverse behavior of WhileNM.

chomp.WhileNotNM(chomp.IsLetter, 1, 8)("20240709 was a great day")
// (" was a great day", "20240709", nil)

type CombinatorParseError ΒΆ

type CombinatorParseError struct {
	// Input to the [Combinator]. This can be empty, as a combinator may
	// not require any input to parse the text.
	Input string

	// Text that was being parsed by the [Combinator]. This will be truncated
	// in the error message.
	Text string

	// Type of [Combinator] that failed.
	Type string
}

CombinatorParseError defines an error that is raised when a combinator fails to parse the input text under its expected condition.

func (CombinatorParseError) Error ΒΆ

func (e CombinatorParseError) Error() string

Error returns a friendly string representation of the current error.

type CutError ΒΆ added in v0.6.0

type CutError struct {
	// Err contains the underlying error that caused the cut.
	Err error
}

CutError is a fatal parsing error that prevents backtracking past the decision point. Used with Cut to improve error messaging.

func (CutError) Error ΒΆ added in v0.6.0

func (e CutError) Error() string

Error returns a friendly string representation of the cut error.

func (CutError) Unwrap ΒΆ added in v0.6.0

func (e CutError) Unwrap() error

Unwrap returns the inner error.

type MappedCombinator ΒΆ added in v0.3.0

type MappedCombinator[S any, T Result] func(string) (string, S, error)

MappedCombinator is a function capable of converting the output from a Combinator into any given type. Upon success, it will return the unparsed text, along with the mapped value. All combinators are strict and must parse its input. Any failure to do so should raise a CombinatorParseError. It is designed for exclusive use by the Map function

func FoldMany ΒΆ added in v0.6.0

func FoldMany[S any, T Result](c Combinator[T], init S, reducer func(S, T) S) MappedCombinator[S, T]

FoldMany will scan the input text, matching the Combinator repeatedly and accumulating results using the provided reducer function. At least one element must match.

chomp.FoldMany(chomp.Digit(), 0, func(acc int, val string) int {
    n, _ := strconv.Atoi(val)
    return acc + n
})("123abc")
// ("abc", 6, nil)

func FoldMany0 ΒΆ added in v0.6.0

func FoldMany0[S any, T Result](c Combinator[T], init S, reducer func(S, T) S) MappedCombinator[S, T]

FoldMany0 will scan the input text, matching the Combinator repeatedly and accumulating results using the provided reducer function. Zero or more elements may match.

chomp.FoldMany0(chomp.Digit(), 0, func(acc int, val string) int {
    n, _ := strconv.Atoi(val)
    return acc + n
})("abc")
// ("abc", 0, nil)

func ManyCount ΒΆ added in v0.6.0

func ManyCount[T Result](c Combinator[T]) MappedCombinator[uint, T]

ManyCount will scan the input text and count the number of times the Combinator matches. At least one match is required. Results are not stored, making this memory efficient for counting.

chomp.ManyCount(chomp.Alpha())("abc123")
// ("123", 3, nil)

func ManyCount0 ΒΆ added in v0.6.0

func ManyCount0[T Result](c Combinator[T]) MappedCombinator[uint, T]

ManyCount0 will scan the input text and count the number of times the Combinator matches. Zero or more matches are allowed. Results are not stored, making this memory efficient for counting.

chomp.ManyCount0(chomp.Alpha())("123")
// ("123", 0, nil)

func Map ΒΆ added in v0.3.0

func Map[S any, T Result](c Combinator[T], mapper func(in T) S) MappedCombinator[S, T]

Map the result of a Combinator to any other type

chomp.Map(
	chomp.While(chomp.IsDigit),
	func (in string) int { return len(in) })("123456")
// ("", 6, nil)

func Value ΒΆ added in v0.6.0

func Value[S any, T Result](c Combinator[T], val S) MappedCombinator[S, T]

Value returns a fixed value upon parser success, discarding the actual parse result. Useful for assigning semantic meaning to parsed tokens.

chomp.Value(chomp.Tag("true"), true)("true")
// ("", true, nil)

chomp.Value(chomp.Tag("false"), false)("false")
// ("", false, nil)

type ParserError ΒΆ

type ParserError struct {
	// Err contains the [CombinatorParseError] that caused the parser to fail.
	Err error

	// Type of [Parser] that failed.
	Type string
}

ParserError defines an error that is raised when a parser fails to parse the input text due to a failed Combinator.

func (ParserError) Error ΒΆ

func (e ParserError) Error() string

Error returns a friendly string representation of the current error.

func (ParserError) Unwrap ΒΆ

func (e ParserError) Unwrap() error

Unwrap returns the inner CombinatorParseError.

type Predicate ΒΆ

type Predicate interface {
	// Match a rune against a defined expression, returning true
	// if the condition is met
	Match(r rune) bool

	// Returns the name of the predicate for error handling
	fmt.Stringer
}

Predicate defines an expression that will return either true or false

type RangedParserError ΒΆ added in v0.2.0

type RangedParserError struct {
	// Err contains the [CombinatorParseError] that caused the parser to fail.
	Err error

	// Range contains the execution details of the ranged parser.
	Exec RangedParserExec

	// Type of [Parser] that failed.
	Type string
}

RangedParserError defines an error that is raised when a ranged parser fails to parse the input text due to a failed Combinator within the expected execution range.

func (RangedParserError) Error ΒΆ added in v0.2.0

func (e RangedParserError) Error() string

Error returns a friendly string representation of the current error.

func (RangedParserError) Unwrap ΒΆ added in v0.2.0

func (e RangedParserError) Unwrap() error

Unwrap returns the inner CombinatorParseError.

type RangedParserExec ΒΆ added in v0.2.0

type RangedParserExec struct {
	// Min is the minimum number of expected executions.
	Min uint

	// Max is the maximum number of possible executions.
	Max uint

	// Count contains the number of executions.
	Count uint
}

RangedParserExec details how a ranged Combinator was executed.

func RangeExecution ΒΆ added in v0.2.0

func RangeExecution(i ...uint) RangedParserExec

RangeExecution is a utility method for setting a RangedParserExec.

  • With one argument, the [RangeParserExec.Count] is set.
  • With two arguments, the [RangeParserExec.Count] and [RangeParserExec.Min] are set.
  • With three arguments, the [RangeParserExec.Count]], [RangeParserExec.Min] and [RangeParserExec.Max] are set.
  • If four or more arguments are provided, a default RangedParserExec will be returned.

func (RangedParserExec) String ΒΆ added in v0.2.0

func (e RangedParserExec) String() string

String returns a string representation of a RangedParserExec.

type Result ΒΆ

type Result interface {
	string | []string
}

Result is the expected output from a Combinator.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL