Glindo
Glindo is a functional parser-combinator library for Gleam that makes it easy to build powerful, composable parsers for context-free grammars: JSON, CSV, small DSLs, YAML, and more. Glindo uses familiar FP abstractions—functors, monads, lazy evaluation—to thread parsing state and errors in a purely functional way.
🔑 Key Features
-
Core Combinators
map
,bind
(monadic sequencing)seq_of
(sequence),chc_of
(choice),chc_opt
(greedy choice)mny_of
,mny_chc
(zero-or-more repetition)opt_of
(optional),sep_by
(separated lists),btwn
(between),peek_fwd
,lazy
,tok
(token with whitespace)
-
Rich Type Safety
Parser(a)
wrapsfn(ParserState) -> Result(ParseResult(a), String)
ParseResult(a)
bundles(res, rem, idx)
ParserState(str, idx)
tracks the remaining input & position
-
Out-of-the-box Grammars
- JSON: full support for
null
,boolean
,number
,string
,array
,object
- CSV: handles quoted strings (with
""
escapes), unquoted fields, line breaks, and trimming
- JSON: full support for
-
Pure-FP Style
- No mutable state—everything is threaded through combinators
- Lazy parsing for recursive grammars
- Customizable error messages
📦 Installation
gleam add glindo
In your gleam.toml
[dependencies] glindo = “>= 1.0.0”
🚀 Quick Start
import glindo/parser
import glindo/types
import glindo/csv
import glindo/json
pub fn main() {
// Parse CSV
let csv_text = "name,age\nAlice,30\nBob,25"
case P.run(glindo.csv(), csv_text) {
Ok(T.ParseResult(csv, _, _)) ->
io.println("Parsed CSV: \(inspect(csv))")
Error(err) ->
io.println("CSV parse error: \(err)")
}
// Parse JSON
let json_text = "{\"foo\": [1, 2, 3], \"bar\": true}"
case glindo.parse_json(json_text) {
Ok(value) ->
io.println("Parsed JSON: \(inspect(value))")
Error(err) ->
io.println("JSON parse error: \(err)")
}
}
📚 Core API Overview
Combinator | Type Signature | Description |
---|---|---|
map | (Parser(a), fn(a) -> b) -> Parser(b) | Transform parsed result |
bind | (Parser(a), fn(a) -> Parser(b)) -> Parser(b) | Sequence two parsers |
seq_of | List(Parser(a)) -> Parser(List(a)) | Run parsers in order; fail if any fails |
chc_of | List(Parser(a)) -> Parser(a) | Try parsers until one succeeds |
chc_opt | List(Parser(a)) -> Parser(a) | Greedy choice: pick the one that consumes the most input |
mny_of | Parser(a) -> Parser(List(a)) | Zero-or-more repetition |
mny_chc | List(Parser(a)) -> Parser(List(a)) | Zero-or-more choice |
opt_of | Parser(a) -> Parser(Option(a)) | Optional parser |
sep_by | (Parser(a), Parser(b)) -> Parser(List(a)) | Parse a list separated by a delimiter |
btwn | (Parser(a), Parser(b), Parser(c)) -> Parser(b) | Between two delimiters |
peek_fwd | Parser(a) -> Parser(a) | Look ahead without consuming input |
lazy | (fn() -> Parser(a)) -> Parser(a) | Deferred parser for recursion |
tok | Parser(a) -> Parser(a) | Skip leading/trailing whitespace around a parser |
See the HexDocs API Reference for full details and examples.
🛠️ Development
Glindo is under active development. To run tests and play with the library locally:
git clone https://github.com/daniel-shunom/glindo.git
cd glindo
gleam run # Run examples or REPL
gleam test # Execute the test suite
🤝 Contributing
- Fork the repository
- Create a feature branch (
git checkout -b my-feature
) - Write tests for new functionality
- Submit a pull request
Please follow the Gleam style guide and include documentation comments for any new public API.
📄 License
This project is released under the MIT License. Feel free to use, modify, and distribute as you see fit.
📞 Contact Information
If you’d like to reach out, feel free to connect via:
- Email: danilshunom2@gmail.com
- LinkedIn: LinkedIn Profile
- GitHub: GitHub Profile
- Twitter: @shunom1
- Website: danielshunom.com