Skip to content

Commit

Permalink
Improve README
Browse files Browse the repository at this point in the history
  • Loading branch information
oleiade committed Aug 28, 2022
1 parent 17685ce commit 918b7c9
Showing 1 changed file with 64 additions and 49 deletions.
113 changes: 64 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,69 +11,87 @@ for both textual and binary formats. It extensively uses the recent introduction
language to offer flexibility in how combinators can be mixed and matched to produce the desired output while
providing as much compile-time type safety as possible.

## Why would you want to use Gomme?

Parser combinators arguably come with a somewhat steep learning curve, but they are a very powerful tool for parsing textual and binary formats. We believe that the benefits of parser combinators outweigh the cost of learning them, and that's why we built Gomme. Our intuition is that most of the cost of learning them is due to the lack of good documentation and examples, and that's why we are trying to provide a comprehensive documentation and a large set of examples.

In practice we have found that parser combinators are very intuitive and flexible, and can be used to build parsers for a wide range of formats. They are also very easy to test, and can be used to build parsers that are very easy to maintain and extend. We have also found that parser combinators are very fast, and can be used to build parsers that can turn out as fast as hand-written parsers.
## Table of Content

<!-- toc -->

- [Example](#example)
- [Installation](#installation)
- [Documentation](#documentation)
- [Installation](#installation)
- [FAQ](#faq)
- [Acknowledgements](#acknowledgements)
- [Authors](#authors)

## Example

FIXME: replace with something simpler and more explicit?
Here's an example of how to parse [hexadecimal color codes](https://developer.mozilla.org/en-US/docs/Web/CSS/color), using the Gomme library:

```golang
type HexColor struct {
red uint8
green uint8
blue uint8
// RGBColor stores the three bytes describing a color in the RGB space.
type RGBColor struct {
red uint8
green uint8
blue uint8
}

func ParseHexColor(input string) (HexColor, error) {
prefixRes := gomme.Token("#")(input)
if prefixRes.Err != nil {
return HexColor{}, prefixRes.Err
}

input = prefixRes.Remaining
parser := gomme.Map(
gomme.Count(HexColorComponent(), 3),
func(components []uint8) (HexColor, error) {
return HexColor{components[0], components[1], components[2]}, nil
},
)

res := parser(input)
if res.Err != nil {
return HexColor{}, res.Err
}

return res.Output, nil
// ParseRGBColor creates a new RGBColor from a hexadecimal color string.
// The string must be a six digit hexadecimal number, prefixed with a "#".
func ParseRGBColor(input string) (RGBColor, error) {
parser := gomme.Preceded(
gomme.Token[string]("#"),
gomme.Map(
gomme.Count(HexColorComponent(), 3),
func(components []uint8) (RGBColor, error) {
return RGBColor{components[0], components[1], components[2]}, nil
},
),
)

result := parser(input)
if result.Err != nil {
return RGBColor{}, result.Err
}

return result.Output, nil
}

// HexColorComponent produces a parser that parses a single hex color component,
// which is a two digit hexadecimal number.
func HexColorComponent() gomme.Parser[string, uint8] {
return func(input string) gomme.Result[uint8, string] {
return gomme.Map(
gomme.TakeWhileMN(2, 2, gomme.IsHexDigit),
fromHex,
)(input)
}
return func(input string) gomme.Result[uint8, string] {
return gomme.Map(
gomme.TakeWhileMN[string](2, 2, gomme.IsHexDigit),
fromHex,
)(input)
}
}

// fromHex converts a two digits hexadecimal number to its decimal value.
func fromHex(input string) (uint8, error) {
res, err := strconv.ParseInt(input, 16, 16)
if err != nil {
return 0, err
}
res, err := strconv.ParseInt(input, 16, 16)
if err != nil {
return 0, err
}

return uint8(res), nil
return uint8(res), nil
}

```

More examples can be found in the [examples](./examples) directory.


## Documentation

[Documentation](https://linktodocumentation)



## Installation

Add the library to your Go project with the following command:
Expand All @@ -82,26 +100,23 @@ Add the library to your Go project with the following command:
go get github.com/oleiade/gomme@latest
```

## Documentation

[Documentation](https://linktodocumentation)

## FAQ

#### What are parser combinators?

TODO
Answer 1
Parser combinators are a programming paradigm for building parsers. As opposed to hand-written or generated parser, they adopt a functional programming approach to parsing, and are based on the idea of composing parsers together to build more complex parsers. What that means in practice, is that instead of writing a parser that parses a whole format, by analyzing and branching based on each characters of your input, you write a set of parsers that parse the smallest possible unit of the format, and then compose them together to build more complex parsers.

#### Why would I want to use parser combinators, and not write my own specific parser?
A key concept to understand is that parser combinators are not parsers themselves, but rather a toolkit that allows you to build parsers. This is why parser combinators are often referred to as a "parser building toolkit". Parser combinator generally are functions producing other functions ingesting some input byte by byte based on some predicate, and returning a result. The result is a structure containing the output of the parser, the remaining part (once the combinator's predicate is not matched anymore, it stops and returns both what it "consumed", and what was left of the input), and an error if the parser failed to parse the input. The output of the parser is the result of the parsing process, and can be of any type. The error is a Go error, and can be used to provide more information about the parsing failure.

TODO
Answer 2
#### Why would I want to use parser combinators, and not write my own specific parser?

#### How fast are parser combinators?
Parser combinators are very flexible, and once you get a good hang on them, they'll allow you to write parsers that are very easy to maintain, modify and extend very easily, and very fast. They are also allegedly quite intuitive, and descriptive of what the underlying data format they parse looks like. Because they're essentially a bunch of functions, generating other functions, composed in various ways depending on the need, they afford you a lot of freedom in how you want to build your specific parser, and how you want to use it.
#### Where can I read/watch about Parser Combinators?

TODO
Answer 3
We recommend the following resources:
- [You could have invented parser combinators](https://theorangeduck.com/page/you-could-have-invented-parser-combinators)
- [Functional Parsing](https://www.youtube.com/watch?v=dDtZLm7HIJs)
- [Building a Mapping Language in Go with Parser Combinators](https://www.youtube.com/watch?v=JiViND-bpmw)

## Acknowledgements

Expand Down

0 comments on commit 918b7c9

Please sign in to comment.