Skip to content

Commit 876b7c4

Browse files
authored
Condense Serializer by using functional constructs and if/when as expression (#35)
1 parent f07a845 commit 876b7c4

File tree

1 file changed

+86
-121
lines changed
  • fluent.syntax/src/main/kotlin/org/projectfluent/syntax/serializer

1 file changed

+86
-121
lines changed

fluent.syntax/src/main/kotlin/org/projectfluent/syntax/serializer/Serializer.kt

Lines changed: 86 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -2,103 +2,80 @@ package org.projectfluent.syntax.serializer
22

33
import org.projectfluent.syntax.ast.* // ktlint-disable no-wildcard-imports
44

5-
private fun indent(content: CharSequence): String {
6-
return content.split("\n").joinToString("\n ")
7-
}
5+
private fun indent(content: CharSequence) = content.split("\n").joinToString("\n ")
86

9-
private fun includesLine(elem: PatternElement): Boolean {
10-
return elem is TextElement && elem.value.contains("\n")
11-
}
7+
private fun PatternElement.includesLine() = this is TextElement && value.contains("\n")
128

13-
private fun isSelectExpr(elem: PatternElement): Boolean {
14-
return elem is Placeable &&
15-
elem.expression is SelectExpression
16-
}
9+
private fun PatternElement.isSelectExpr() = this is Placeable && expression is SelectExpression
1710

1811
/**
1912
* Serialize Fluent nodes to `CharSequence`.
2013
*
2114
* @property withJunk serialize Junk entries or not.
2215
*/
23-
class FluentSerializer(var withJunk: Boolean = false) {
16+
class FluentSerializer(private val withJunk: Boolean = false) {
2417
/**
2518
* Serialize a Resource.
2619
*/
27-
fun serialize(resource: Resource): CharSequence {
28-
val builder = StringBuilder()
29-
30-
entries@ for (entry in resource.body) {
31-
val serialized = when (entry) {
32-
is Entry -> serializeEntry(entry)
33-
is Whitespace -> entry.content
34-
is Junk -> {
35-
if (this.withJunk) {
36-
entry.content
37-
} else {
38-
continue@entries
39-
}
20+
fun serialize(resource: Resource): CharSequence =
21+
resource.body
22+
.mapNotNull {
23+
when (it) {
24+
is Entry -> serializeEntry(it)
25+
is Whitespace -> it.content
26+
is Junk -> it.content.takeIf { this.withJunk }
27+
else -> throw SerializeError("Unknown top-level entry type")
4028
}
41-
else -> throw SerializeError("Unknown top-level entry type")
4229
}
43-
builder.append(serialized)
44-
}
45-
46-
return builder
47-
}
30+
.joinToString("")
4831

4932
/**
5033
* Serialize Message, Term, Whitespace, and Junk.
5134
*/
52-
fun serialize(entry: TopLevel): CharSequence {
35+
fun serialize(entry: TopLevel): CharSequence =
5336
when (entry) {
54-
is Entry -> return serializeEntry(entry)
55-
is Whitespace -> return entry.content
56-
is Junk -> return entry.content
37+
is Entry -> serializeEntry(entry)
38+
is Whitespace -> entry.content
39+
is Junk -> entry.content
40+
else -> throw SerializeError("Unknown top-level type: $entry")
5741
}
58-
throw SerializeError("Unknown top-level type: $entry")
59-
}
6042

6143
/**
6244
* Serialize an Expression.
6345
*
6446
* This is useful to get a string representation of a simple Placeable.
6547
*/
66-
fun serialize(expr: Expression): CharSequence {
67-
return serializeExpression(expr)
68-
}
48+
fun serialize(expr: Expression): CharSequence = serializeExpression(expr)
6949

7050
/**
7151
* Serialize a VariantKey.
7252
*
7353
* Useful when displaying the options of a SelectExpression.
7454
*/
75-
fun serialize(key: VariantKey): CharSequence {
76-
return serializeVariantKey(key)
77-
}
55+
fun serialize(key: VariantKey): CharSequence = serializeVariantKey(key)
7856

79-
private fun serializeEntry(entry: Entry): CharSequence {
57+
private fun serializeEntry(entry: Entry) =
8058
when (entry) {
81-
is Message -> return serializeMessage(entry)
82-
is Term -> return serializeTerm(entry)
83-
is Comment -> return serializeComment(entry, "#")
84-
is GroupComment -> return serializeComment(entry, "##")
85-
is ResourceComment -> return serializeComment(entry, "###")
86-
}
87-
throw SerializeError("Unknown entry type: $entry")
88-
}
89-
90-
private fun serializeComment(comment: BaseComment, prefix: String = "#"): CharSequence {
91-
val builder = StringBuilder()
92-
val lines = comment.content.split("\n")
93-
for (line in lines) {
94-
if (line.isNotEmpty()) {
95-
builder.append("$prefix $line", "\n")
96-
} else {
97-
builder.append(prefix, "\n")
98-
}
99-
}
100-
return builder
101-
}
59+
is Message -> serializeMessage(entry)
60+
is Term -> serializeTerm(entry)
61+
is Comment -> serializeComment(entry, "#")
62+
is GroupComment -> serializeComment(entry, "##")
63+
is ResourceComment -> serializeComment(entry, "###")
64+
else -> throw SerializeError("Unknown entry type: $entry")
65+
}
66+
67+
private fun serializeComment(comment: BaseComment, prefix: CharSequence = "#") =
68+
comment.content.split("\n")
69+
.joinToString(
70+
"",
71+
transform = {
72+
if (it.isNotEmpty()) {
73+
"$prefix $it\n"
74+
} else {
75+
"$prefix\n"
76+
}
77+
}
78+
)
10279

10380
private fun serializeMessage(message: Message): CharSequence {
10481
val builder = StringBuilder()
@@ -145,44 +122,39 @@ class FluentSerializer(var withJunk: Boolean = false) {
145122
}
146123

147124
private fun serializePattern(pattern: Pattern): CharSequence {
148-
val startOnLine =
149-
pattern.elements.any(::isSelectExpr) ||
150-
pattern.elements.any(::includesLine)
125+
val startOnLine = pattern.elements.any { it.isSelectExpr() || it.includesLine() }
151126
val elements = pattern.elements.map(::serializeElement)
152127
val content = indent(elements.joinToString(""))
153128

154-
if (startOnLine) {
155-
return "\n $content"
129+
return if (startOnLine) {
130+
"\n $content"
131+
} else {
132+
" $content"
156133
}
157-
158-
return " $content"
159134
}
160135

161-
private fun serializeElement(element: PatternElement): CharSequence {
136+
private fun serializeElement(element: PatternElement) =
162137
when (element) {
163-
is TextElement -> return element.value
164-
is Placeable -> return serializePlaceable(element)
138+
is TextElement -> element.value
139+
is Placeable -> serializePlaceable(element)
140+
else -> throw SerializeError("Unknown element type: $element")
165141
}
166-
throw SerializeError("Unknown element type: $element")
167-
}
168142

169-
private fun serializePlaceable(placeable: Placeable): CharSequence {
170-
val expr = placeable.expression
171-
when (expr) {
172-
is Placeable -> return "{${serializePlaceable(expr)}}"
143+
private fun serializePlaceable(placeable: Placeable): CharSequence =
144+
when (val expr = placeable.expression) {
145+
is Placeable -> "{${serializePlaceable(expr)}}"
173146
// Special-case select expression to control the whitespace around the
174147
// opening and the closing brace.
175-
is SelectExpression -> return "{ ${serializeExpression(expr)}}"
176-
is Expression -> return "{ ${serializeExpression(expr)} }"
148+
is SelectExpression -> "{ ${serializeExpression(expr)}}"
149+
is Expression -> "{ ${serializeExpression(expr)} }"
150+
else -> throw SerializeError("Unknown placeable type")
177151
}
178-
throw SerializeError("Unknown placeable type")
179-
}
180152

181153
private fun serializeExpression(expr: Expression): CharSequence {
182-
when (expr) {
183-
is StringLiteral -> return "\"${expr.value}\""
184-
is NumberLiteral -> return expr.value
185-
is VariableReference -> return "$${expr.id.name}"
154+
return when (expr) {
155+
is StringLiteral -> "\"${expr.value}\""
156+
is NumberLiteral -> expr.value
157+
is VariableReference -> "$${expr.id.name}"
186158
is TermReference -> {
187159
val builder = StringBuilder()
188160
builder.append("-", expr.id.name)
@@ -192,68 +164,61 @@ class FluentSerializer(var withJunk: Boolean = false) {
192164
expr.arguments?.let {
193165
builder.append(serializeCallArguments(it))
194166
}
195-
return builder
167+
builder
196168
}
197169
is MessageReference -> {
198170
val builder = StringBuilder()
199171
builder.append(expr.id.name)
200172
expr.attribute?.let {
201173
builder.append(".", it.name)
202174
}
203-
return builder
175+
builder
204176
}
205-
is FunctionReference ->
206-
return "${expr.id.name}${serializeCallArguments(expr.arguments)}"
177+
is FunctionReference -> "${expr.id.name}${serializeCallArguments(expr.arguments)}"
207178
is SelectExpression -> {
208179
val builder = StringBuilder()
209-
val selector = serializeExpression(expr.selector)
210-
builder.append(selector, " ->")
211-
for (variant in expr.variants) {
212-
builder.append(serializeVariant(variant))
213-
}
180+
builder.append(serializeExpression(expr.selector), " ->")
181+
expr.variants.forEach { builder.append(serializeVariant(it)) }
214182
builder.append("\n")
215-
return builder
216183
}
184+
else -> throw SerializeError("Unknown expression type: $expr")
217185
}
218-
throw SerializeError("Unknown expression type: $expr")
219186
}
220187

221188
private fun serializeVariant(variant: Variant): CharSequence {
222189
val key = serializeVariantKey(variant.key)
223190
val value = indent(serializePattern(variant.value))
224191

225-
if (variant.default) {
226-
return "\n *[$key]$value"
192+
return if (variant.default) {
193+
"\n *[$key]$value"
194+
} else {
195+
"\n [$key]$value"
227196
}
228-
229-
return "\n [$key]$value"
230197
}
231198

232199
private fun serializeCallArguments(expr: CallArguments): CharSequence {
233200
val positional = expr.positional.joinToString(", ", transform = ::serializeExpression)
234201
val named = expr.named.joinToString(", ", transform = ::serializeNamedArgument)
235-
if (expr.positional.size > 0 && expr.named.size > 0) {
236-
return "($positional, $named)"
237-
}
238-
if (expr.positional.size > 0) {
239-
return "($positional)"
240-
}
241-
if (expr.named.size > 0) {
242-
return "($named)"
202+
val hasPositional = expr.positional.size > 0
203+
val hasNamed = expr.named.size > 0
204+
205+
return if (hasPositional && hasNamed) {
206+
"($positional, $named)"
207+
} else if (hasPositional) {
208+
"($positional)"
209+
} else if (hasNamed) {
210+
"($named)"
211+
} else {
212+
"()"
243213
}
244-
return "()"
245214
}
246215

247-
private fun serializeNamedArgument(arg: NamedArgument): CharSequence {
248-
val value = serializeExpression(arg.value)
249-
return "${arg.name.name}: $value"
250-
}
216+
private fun serializeNamedArgument(arg: NamedArgument) = "${arg.name.name}: ${serializeExpression(arg.value)}"
251217

252-
private fun serializeVariantKey(key: VariantKey): CharSequence {
218+
private fun serializeVariantKey(key: VariantKey) =
253219
when (key) {
254-
is Identifier -> return key.name
255-
is NumberLiteral -> return key.value
220+
is Identifier -> key.name
221+
is NumberLiteral -> key.value
222+
else -> throw SerializeError("Unknown variant key type: $key")
256223
}
257-
throw SerializeError("Unknown variant key type: $key")
258-
}
259224
}

0 commit comments

Comments
 (0)