Skip to content

Commit fe6a231

Browse files
committed
✨ functionality for extracting data or erroring
1 parent 5fd202d commit fe6a231

File tree

2 files changed

+36
-27
lines changed

2 files changed

+36
-27
lines changed

src/parz/combinators.gleam

+13
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,19 @@ pub fn map(parser: Parser(a), transform) {
135135
}
136136
}
137137

138+
pub fn try_map(parser: Parser(a), transform) {
139+
fn(input) {
140+
case parser(input) {
141+
Error(err) -> Error(err)
142+
Ok(ok) ->
143+
case transform(ok.matched) {
144+
Error(err) -> Error(err)
145+
Ok(t) -> Ok(ParserState(t, ok.remaining))
146+
}
147+
}
148+
}
149+
}
150+
138151
pub fn as_list(parser: Parser(a)) {
139152
fn(input) {
140153
case parser(input) {

test/simple_parser_test.gleam

+23-27
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,32 @@
11
import gleeunit/should
22
import parz.{run}
3-
import parz/combinators.{label_error, left, map, separator1, sequence}
3+
import parz/combinators.{
4+
choice, label_error, left, map, separator1, sequence, try_map,
5+
}
46
import parz/parsers.{letters, regex, str}
57
import parz/types.{ParserState}
68

79
type Kind {
810
StringKind
911
BooleanKind
1012
NumberKind
11-
UnknownKind
1213
}
1314

1415
type Identifier {
1516
Identifier(name: String)
1617
}
1718

1819
type Node {
19-
UnknownNode
2020
Node(name: Identifier, kind: Kind)
2121
}
2222

2323
type NodePart {
24-
K(kind: Kind)
25-
I(identifier: Identifier)
24+
NodeKind(kind: Kind)
25+
NodeIdentifier(identifier: Identifier)
2626
}
2727

28-
type AST {
29-
AST(List(Node))
28+
type Ast {
29+
Ast(List(Node))
3030
}
3131

3232
const input = "name:string;
@@ -36,35 +36,31 @@ active:boolean;"
3636
const custom_error = "Expected : but found something else"
3737

3838
fn parser() {
39-
let name =
40-
left(letters(), str(":") |> label_error(custom_error))
39+
let identifier =
40+
letters()
4141
|> map(Identifier)
42-
|> map(I)
4342

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)
43+
let string_kind = str("string") |> map(fn(_) { StringKind })
44+
let number_kind = str("number") |> map(fn(_) { NumberKind })
45+
let boolean_kind = str("boolean") |> map(fn(_) { BooleanKind })
5546

47+
let kind = choice([string_kind, number_kind, boolean_kind])
5648
let node =
57-
sequence([name, kind])
58-
|> map(fn(ok) {
49+
sequence([
50+
left(identifier, str(":") |> label_error(custom_error))
51+
|> map(NodeIdentifier),
52+
left(kind, str(";")) |> map(NodeKind),
53+
])
54+
|> try_map(fn(ok) {
5955
case ok {
60-
[I(i), K(k)] -> Node(i, k)
61-
_ -> UnknownNode
56+
[NodeIdentifier(i), NodeKind(k)] -> Ok(Node(i, k))
57+
_ -> Error("Failed to match identifier:kind")
6258
}
6359
})
6460

6561
let whitespace = regex("\\s*")
6662

67-
let parser = separator1(node, whitespace) |> map(AST)
63+
let parser = separator1(node, whitespace) |> map(Ast)
6864

6965
parser
7066
}
@@ -73,7 +69,7 @@ pub fn simple_parser_test() {
7369
run(parser(), input)
7470
|> should.be_ok
7571
|> should.equal(ParserState(
76-
AST([
72+
Ast([
7773
Node(Identifier("name"), StringKind),
7874
Node(Identifier("age"), NumberKind),
7975
Node(Identifier("active"), BooleanKind),

0 commit comments

Comments
 (0)