Skip to content

Commit df28b30

Browse files
committed
simplify code and make more tests
1 parent 007db9e commit df28b30

File tree

2 files changed

+205
-123
lines changed

2 files changed

+205
-123
lines changed

lib/src/main/kotlin/konnik/json/Parser.kt

Lines changed: 98 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -8,40 +8,42 @@ fun <A : Any, B : Any> Parser<A>.map(transform: (A) -> B): Parser<B> = { input -
88
this(input)?.let { transform(it.first) to it.second }
99
}
1010

11+
// A parser that always succeeds with a value without consuming any input
12+
fun <T : Any> succeed(value: T): Parser<T> = { input -> value to input }
13+
1114
fun <A : Any, B : Any> Parser<A>.andThen(aToParserB: (A) -> Parser<B>): Parser<B> = { input ->
1215
this(input)?.let { a -> aToParserB(a.first)(a.second) }
1316
}
1417

15-
fun <A : Any, B : Any> Parser<A>.keep(parserB: Parser<B>): Parser<B> = { input ->
16-
this(input)?.let { resultA -> parserB(resultA.second) }
17-
}
18+
fun <A : Any, B : Any> Parser<A>.keep(parserB: Parser<B>): Parser<B> =
19+
this.andThen { parserB }
1820

19-
fun <A : Any, B : Any> Parser<A>.skip(parserB: Parser<B>): Parser<A> = { input ->
20-
this(input)?.let { resultA -> parserB(resultA.second)?.let { resultB -> resultA.first to resultB.second } }
21-
}
2221

23-
fun <A:Any> oneOf(vararg parsers : Parser<A>) : Parser<A> = { input ->
22+
fun <A : Any, B : Any> Parser<A>.skip(parserB: Parser<B>): Parser<A> =
23+
this.andThen { a -> parserB.map { a } }
24+
25+
fun <A : Any> oneOf(vararg parsers: Parser<A>): Parser<A> = { input ->
2426
parsers.firstNotNullOfOrNull { it(input) }
2527
}
2628

27-
fun <A:Any> lazy(parser : () -> Parser<A>) : Parser<A> = { input ->
29+
fun <A : Any> lazy(parser: () -> Parser<A>): Parser<A> = { input ->
2830
parser()(input)
2931
}
3032

31-
operator fun Parser<String>.plus(parserB : Parser<String>) : Parser<String> =
32-
this.andThen { valueA -> parserB.map {valueB -> valueA + valueB }}
33+
operator fun Parser<String>.plus(parserB: Parser<String>): Parser<String> =
34+
this.andThen { valueA -> parserB.map { valueB -> valueA + valueB } }
3335

3436
// primitive parsers
3537

36-
fun s(str : String): Parser<String> = { input ->
38+
fun s(str: String): Parser<String> = { input ->
3739
when {
3840
input.startsWith(str) -> str to input.drop(str.length)
3941
else -> null
4042
}
4143
}
4244

43-
fun match(test: (Char) -> Boolean) : Parser<Char> = { input ->
44-
input.firstOrNull()?.let {
45+
fun match(test: (Char) -> Boolean): Parser<Char> = { input ->
46+
input.firstOrNull()?.let {
4547
when {
4648
test(it) -> input.first() to input.drop(1)
4749
else -> null
@@ -58,186 +60,187 @@ val ws: Parser<String> = oneOf(
5860
succeed("")
5961
)
6062

61-
fun _ws() : Parser<String> = lazy {ws}
62-
63+
fun _ws(): Parser<String> = lazy { ws }
6364

65+
val onenine: Parser<String> =
66+
match { it in '1'..'9' }.map { it.toString() }
6467

65-
// A parser that always succeeds with a value without consuming any input
66-
fun <T:Any> succeed(value : T) : Parser<T> = { input -> value to input }
67-
68-
val onenine : Parser<String> =
69-
match { it in '1' .. '9'}.map { it.toString()}
70-
71-
val digit : Parser<String> = oneOf(
68+
val digit: Parser<String> = oneOf(
7269
s("0"),
7370
onenine
7471
)
7572

76-
val digits : Parser<String> = oneOf(
73+
val digits: Parser<String> = oneOf(
7774
digit + _digits(),
7875
digit
7976
)
8077

8178
fun _digits() = lazy { digits }
8279

83-
val integer : Parser<String> = oneOf(
80+
val integer: Parser<String> = oneOf(
8481
onenine + digits,
8582
digit,
8683
s("-") + onenine + digits,
8784
s("-") + digits,
8885
)
8986

90-
val fraction : Parser<String> = oneOf(
87+
val fraction: Parser<String> = oneOf(
9188
s(".") + digits,
9289
succeed("")
9390
)
94-
val sign : Parser<String> = oneOf(
91+
val sign: Parser<String> = oneOf(
9592
s("+"),
9693
s("-"),
9794
succeed("")
9895
)
9996

100-
val exponent : Parser<String> = oneOf(
97+
val exponent: Parser<String> = oneOf(
10198
s("E") + sign + digits,
10299
s("e") + sign + digits,
103100
succeed("")
104101
)
105102

106103

107-
val number : Parser<String> =
104+
val number: Parser<String> =
108105
integer + fraction + exponent
109106

110107

111-
112-
val hex : Parser<String> = oneOf(
108+
val hex: Parser<String> = oneOf(
113109
digit,
114-
match { it in 'A'..'F' }.map {it.toString()},
115-
match { it in 'a'..'f' }.map {it.toString()},
116-
)
117-
118-
val escape : Parser<String> = oneOf(
119-
s("\"").map {"\""},
120-
s("\\").map {"\\"},
121-
s("/").map {"/"},
122-
s("b").map {"\b"},
123-
s("f").map {"\u000C"},
124-
s("n").map {"\n"},
125-
s("r").map {"\r"},
126-
s("t").map {"\t"},
127-
(s("u").map {""} + hex + hex + hex + hex).map {
110+
match { it in 'A'..'F' }.map { it.toString() },
111+
match { it in 'a'..'f' }.map { it.toString() },
112+
)
113+
114+
val escape: Parser<String> = oneOf(
115+
s("\"").map { "\"" },
116+
s("\\").map { "\\" },
117+
s("/").map { "/" },
118+
s("b").map { "\b" },
119+
s("f").map { "\u000C" },
120+
s("n").map { "\n" },
121+
s("r").map { "\r" },
122+
s("t").map { "\t" },
123+
(s("u").map { "" } + hex + hex + hex + hex).map {
128124
String.format("%c", it.toInt(16))
129125
}
130126
)
131127

132-
val character : Parser<String> = oneOf(
133-
match { it >= '\u0020' && it != '\"' && it != '\\'}.map { it.toString() }, // "
128+
val character: Parser<String> = oneOf(
129+
match { it >= '\u0020' && it != '\"' && it != '\\' }.map { it.toString() }, // "
134130
s("\\").keep(escape)
135131
)
136132

137-
val characters : Parser<String> = oneOf(
133+
val characters: Parser<String> = oneOf(
138134
character + _characters(),
139135
succeed("")
140136
)
137+
141138
fun _characters() = lazy { characters }
142139

143-
val string : Parser<String> =
140+
val string: Parser<String> =
144141
s("\"").keep(characters).skip(s("\""))
145-
142+
146143

147144
// JSON PARSER
148145

149146
sealed interface JsonValue {
150-
data object Null: JsonValue
151-
data class Bool(val value: Boolean): JsonValue
152-
data class Str(val value: String): JsonValue
153-
data class Num(val value: Double): JsonValue
154-
data class Array(val items: List<JsonValue>): JsonValue
155-
data class Object(val members: Map<String, JsonValue>): JsonValue
147+
data object Null : JsonValue
148+
data class Bool(val value: Boolean) : JsonValue
149+
data class Str(val value: String) : JsonValue
150+
data class Num(val value: Double) : JsonValue
151+
data class Array(val items: List<JsonValue>) : JsonValue
152+
data class Object(val members: Map<String, JsonValue>) : JsonValue
156153
}
157154

158155
val jsBool: Parser<JsonValue> = oneOf(
159156
s("true").map { JsonValue.Bool(true) },
160157
s("false").map { JsonValue.Bool(false) }
161-
)
158+
)
162159

163-
val jsNull: Parser<JsonValue> =
160+
val jsNull: Parser<JsonValue> =
164161
s("null").map { JsonValue.Null }
165162

166-
val jsNum: Parser<JsonValue> =
163+
val jsNum: Parser<JsonValue> =
167164
number.map { JsonValue.Num(it.toDouble()) }
168165

169-
val jsString: Parser<JsonValue> =
170-
string.map { JsonValue.Str(it)}
166+
val jsString: Parser<JsonValue> =
167+
string.map { JsonValue.Str(it) }
171168

172-
val jsArray: Parser<JsonValue> = oneOf(
173-
s("[").andThen { ws }.andThen {s("]")}.map {JsonValue.Array(emptyList<JsonValue>())},
174-
s("[").keep(_elements()).skip(s("]")).map {JsonValue.Array(it)},
169+
val jsArray: Parser<JsonValue> = oneOf(
170+
s("[").andThen { ws }.andThen { s("]") }.map { JsonValue.Array(emptyList<JsonValue>()) },
171+
s("[").keep(_elements()).skip(s("]")).map { JsonValue.Array(it) },
175172
)
176173

177-
val element : Parser<JsonValue> =
174+
val element: Parser<JsonValue> =
178175
ws.keep(_jsonValue()).skip(ws)
179176

180177

181-
val elements : Parser<List<JsonValue>> = oneOf(
182-
element.skip(s(",")).andThen { first -> _elements().map { rest ->
183-
listOf(first) + rest
184-
} },
185-
element.map { listOf(it)},
178+
val elements: Parser<List<JsonValue>> = oneOf(
179+
element.skip(s(",")).andThen { first ->
180+
_elements().map { rest ->
181+
listOf(first) + rest
182+
}
183+
},
184+
element.map { listOf(it) },
186185
)
187186

188-
fun _elements() : Parser<List<JsonValue>> = lazy {elements}
187+
fun _elements(): Parser<List<JsonValue>> = lazy { elements }
189188

190-
val member : Parser<Pair<String,JsonValue>> =
191-
ws.keep(string).skip(ws).skip(s(":")).andThen { key -> element.map { value ->
192-
key to value
193-
}}
189+
val member: Parser<Pair<String, JsonValue>> =
190+
ws.keep(string).skip(ws).skip(s(":")).andThen { key ->
191+
element.map { value ->
192+
key to value
193+
}
194+
}
194195

195-
val members : Parser<List<Pair<String,JsonValue>>> = oneOf(
196-
member.skip(s(",")).andThen { first -> _members().map { rest ->
197-
listOf(first) + rest
198-
}},
199-
member.map { listOf(it)}
196+
val members: Parser<List<Pair<String, JsonValue>>> = oneOf(
197+
member.skip(s(",")).andThen { first ->
198+
_members().map { rest ->
199+
listOf(first) + rest
200+
}
201+
},
202+
member.map { listOf(it) }
200203
)
201-
fun _members() : Parser<List<Pair<String,JsonValue>>> = members
202204

203-
val jsObject : Parser<JsonValue> = oneOf(
204-
s("{").keep(members).skip(s("}")).map { JsonValue.Object(it.toMap())},
205-
s("{").skip(ws).keep(s("}")).map {JsonValue.Object(emptyMap())},
205+
fun _members(): Parser<List<Pair<String, JsonValue>>> = members
206+
207+
val jsObject: Parser<JsonValue> = oneOf(
208+
s("{").keep(members).skip(s("}")).map { JsonValue.Object(it.toMap()) },
209+
s("{").skip(ws).keep(s("}")).map { JsonValue.Object(emptyMap()) },
206210
)
207211

208-
val jsonValue : Parser<JsonValue> = oneOf(
212+
val jsonValue: Parser<JsonValue> = oneOf(
209213
jsNull,
210214
jsBool,
211215
jsString,
212216
jsNum,
213217
jsArray,
214218
jsObject
215-
)
216-
fun _jsonValue() = lazy {jsonValue}
219+
)
217220

221+
fun _jsonValue() = lazy { jsonValue }
218222

219-
val json : Parser<JsonValue> = element
220223

224+
val json: Parser<JsonValue> = element
221225

222226

223-
fun <A : Any> Parser<A>.runParser(input: String): A? =
224-
this(input)?.let {
227+
fun <A : Any> Parser<A>.runParser(input: String): A? =
228+
this(input)?.let {
225229
when (it.second) {
226230
"" -> it.first
227231
else -> null // it's an error if not all input is consumed
228-
}
232+
}
229233
}
230234

231235

232-
233-
fun JsonValue.str() : String =
236+
fun JsonValue.str(): String =
234237
(this as JsonValue.Str).value
235238

236-
fun JsonValue.num() : Double =
239+
fun JsonValue.num(): Double =
237240
(this as JsonValue.Num).value
238241

239-
fun JsonValue.array() : List<JsonValue> =
242+
fun JsonValue.array(): List<JsonValue> =
240243
(this as JsonValue.Array).items
241244

242-
fun JsonValue.field(field: String) : JsonValue =
245+
fun JsonValue.field(field: String): JsonValue =
243246
(this as JsonValue.Object).members.get(field)!!

0 commit comments

Comments
 (0)