Skip to content

Commit dd6e8f1

Browse files
committed
✨ working example parser
1 parent 9a762f7 commit dd6e8f1

File tree

4 files changed

+109
-19
lines changed

4 files changed

+109
-19
lines changed

README.md

+20-3
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,36 @@
11
# parz
22

3-
> Learning about Parser Combinators using [The YouTube Series by Low Byte Productions](https://www.youtube.com/playlist?list=PLP29wDx6QmW5yfO1LAgO8kU3aQEj8SIrU)
3+
A simple parser combinator library
4+
5+
> Trying to learn [Gleam]() while also Learning about Parser Combinators using
6+
> [The YouTube Series by Low Byte Productions](https://www.youtube.com/playlist?list=PLP29wDx6QmW5yfO1LAgO8kU3aQEj8SIrU)
7+
> and [Understanding Parser Combinators](https://fsharpforfunandprofit.com/posts/understanding-parser-combinators/)
48
59
[![Package Version](https://img.shields.io/hexpm/v/parz)](https://hex.pm/packages/parz)
610
[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/parz/)
711

12+
The project exposes the following modules:
13+
14+
1. `parz.` - contains the `run` method which is used for executing a parser
15+
2. `parz/combinators` - the parser combinator library
16+
3. `pars/parsers` - some simple, prmiitive parsers
17+
18+
## Usage
19+
820
```sh
921
gleam add parz
1022
```
1123

1224
```gleam
13-
import parz
25+
import parz.{run}
26+
import pars/combinators
27+
import pars/parsers
1428
1529
pub fn main() {
16-
// TODO: An example of the project in use
30+
// For an example usage look at the `tests/sample_parser_test.gleam` file
31+
let parser = // .. define a parser
32+
33+
let result = run(parser, content_to_parse)
1734
}
1835
```
1936

src/parz/combinators.gleam

-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import gleam/list
22
import gleam/string
33
import parz/types.{type Parser, type ParserState, ParserState}
4-
import parz/util.{tap}
54

65
fn sequence_rec(
76
parsers: List(Parser(a)),

src/parz/util.gleam

-15
This file was deleted.

test/simple_parser_test.gleam

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import gleeunit/should
2+
import parz.{run}
3+
import parz/combinators.{label_error, left, map, separator1, sequence}
4+
import parz/parsers.{letters, regex, str}
5+
import parz/types.{ParserState}
6+
7+
type Kind {
8+
StringKind
9+
BooleanKind
10+
NumberKind
11+
UnknownKind
12+
}
13+
14+
type Identifier {
15+
Identifier(name: String)
16+
}
17+
18+
type Node {
19+
UnknownNode
20+
Node(name: Identifier, kind: Kind)
21+
}
22+
23+
type NodePart {
24+
K(kind: Kind)
25+
I(identifier: Identifier)
26+
}
27+
28+
type AST {
29+
AST(List(Node))
30+
}
31+
32+
const input = "name:string;
33+
age:number;
34+
active:boolean;"
35+
36+
const custom_error = "Expected : but found something else"
37+
38+
fn parser() {
39+
let name =
40+
left(letters(), str(":") |> label_error(custom_error))
41+
|> map(Identifier)
42+
|> map(I)
43+
44+
let kind =
45+
left(letters(), str(";"))
46+
|> map(fn(ok) {
47+
case ok {
48+
"string" -> StringKind
49+
"number" -> NumberKind
50+
"boolean" -> BooleanKind
51+
_ -> UnknownKind
52+
}
53+
})
54+
|> map(K)
55+
56+
let node =
57+
sequence([name, kind])
58+
|> map(fn(ok) {
59+
case ok {
60+
[I(i), K(k)] -> Node(i, k)
61+
_ -> UnknownNode
62+
}
63+
})
64+
65+
let whitespace = regex("\\s*")
66+
67+
let parser = separator1(node, whitespace) |> map(AST)
68+
69+
parser
70+
}
71+
72+
pub fn simple_parser_test() {
73+
run(parser(), input)
74+
|> should.be_ok
75+
|> should.equal(ParserState(
76+
AST([
77+
Node(Identifier("name"), StringKind),
78+
Node(Identifier("age"), NumberKind),
79+
Node(Identifier("active"), BooleanKind),
80+
]),
81+
"",
82+
))
83+
}
84+
85+
pub fn simple_parser_error_test() {
86+
run(parser(), "name;number")
87+
|> should.be_error
88+
|> should.equal(custom_error)
89+
}

0 commit comments

Comments
 (0)