<lambda>null1 package com.android.codegen
2
3 import com.github.javaparser.JavaParser
4 import com.github.javaparser.ParseProblemException
5 import com.github.javaparser.ParseResult
6 import com.github.javaparser.ast.Node
7 import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration
8 import com.github.javaparser.ast.body.TypeDeclaration
9 import com.github.javaparser.ast.expr.*
10 import com.github.javaparser.ast.nodeTypes.NodeWithModifiers
11 import java.time.Instant
12 import java.time.ZoneId
13 import java.time.format.DateTimeFormatter
14 import java.time.format.FormatStyle
15
16 /**
17 * [Iterable.forEach] + [Any.apply]
18 */
19 inline fun <T> Iterable<T>.forEachApply(block: T.() -> Unit) = forEach(block)
20
21 inline fun String.mapLines(f: String.() -> String?) = lines().mapNotNull(f).joinToString("\n")
22 inline fun <T> Iterable<T>.trim(f: T.() -> Boolean) = dropWhile(f).dropLastWhile(f)
23 fun String.trimBlankLines() = lines().trim { isBlank() }.joinToString("\n")
24
Charnull25 fun Char.isNewline() = this == '\n' || this == '\r'
26 fun Char.isWhitespaceNonNewline() = isWhitespace() && !isNewline()
27
28 fun if_(cond: Boolean, then: String) = if (cond) then else ""
29
30 fun <T> Any?.as_(): T = this as T
31
32 inline infix fun Int.times(action: () -> Unit) {
33 for (i in 1..this) action()
34 }
35
36 /**
37 * a bbb
38 * cccc dd
39 *
40 * ->
41 *
42 * a bbb
43 * cccc dd
44 */
Iterablenull45 fun Iterable<Pair<String, String>>.columnize(separator: String = " | "): String {
46 val col1w = map { (a, _) -> a.length }.max()!!
47 val col2w = map { (_, b) -> b.length }.max()!!
48 return map { it.first.padEnd(col1w) + separator + it.second.padEnd(col2w) }.joinToString("\n")
49 }
50
hasUnbalancedCurlyBracenull51 fun String.hasUnbalancedCurlyBrace(): Boolean {
52 var braces = 0
53 forEach {
54 if (it == '{') braces++
55 if (it == '}') braces--
56 if (braces < 0) return true
57 }
58 return false
59 }
60
toLowerCamelnull61 fun String.toLowerCamel(): String {
62 if (length >= 2 && this[0] == 'm' && this[1].isUpperCase()) return substring(1).capitalize()
63 if (all { it.isLetterOrDigit() }) return decapitalize()
64 return split("[^a-zA-Z0-9]".toRegex())
65 .map { it.toLowerCase().capitalize() }
66 .joinToString("")
67 .decapitalize()
68 }
69
forEachLastAwarenull70 inline fun <T> List<T>.forEachLastAware(f: (T, Boolean) -> Unit) {
71 forEachIndexed { index, t -> f(t, index == size - 1) }
72 }
73
74 @Suppress("UNCHECKED_CAST")
singleArgAsnull75 fun <T : Expression> AnnotationExpr.singleArgAs()
76 = ((this as SingleMemberAnnotationExpr).memberValue as T)
77
78 inline operator fun <reified T> Array<T>.minus(item: T) = toList().minus(item).toTypedArray()
79
80 fun currentTimestamp() = DateTimeFormatter
81 .ofLocalizedDateTime(/* date */ FormatStyle.MEDIUM, /* time */ FormatStyle.LONG)
82 .withZone(ZoneId.systemDefault())
83 .format(Instant.now())
84
85 val NodeWithModifiers<*>.visibility get() = accessSpecifier
86
87 fun abort(msg: String): Nothing {
88 System.err.println("ERROR: $msg")
89 System.exit(1)
90 throw InternalError() // can't get here
91 }
92
bitAtExprnull93 fun bitAtExpr(bitIndex: Int) = "0x${java.lang.Long.toHexString(1L shl bitIndex)}"
94
95 val AnnotationExpr.args: Map<String, Expression> get() = when (this) {
96 is MarkerAnnotationExpr -> emptyMap()
97 is SingleMemberAnnotationExpr -> mapOf("value" to memberValue)
98 is NormalAnnotationExpr -> pairs.map { it.name.asString() to it.value }.toMap()
99 else -> throw IllegalArgumentException("Unknown annotation expression: $this")
100 }
101
102 val TypeDeclaration<*>.nestedTypes get() = childNodes.filterIsInstance<TypeDeclaration<*>>()
103 val TypeDeclaration<*>.nestedDataClasses get()
104 = nestedTypes.filterIsInstance<ClassOrInterfaceDeclaration>()
<lambda>null105 .filter { it.annotations.any { it.nameAsString.endsWith("DataClass") } }
106 val TypeDeclaration<*>.nestedNonDataClasses get()
107 = nestedTypes.filterIsInstance<ClassOrInterfaceDeclaration>()
<lambda>null108 .filter { it.annotations.none { it.nameAsString.endsWith("DataClass") } }
<lambda>null109 .filterNot { it.isInterface }
110 val TypeDeclaration<*>.startLine get() = range.get()!!.begin.line
111
forEachSequentialPairnull112 inline fun <T> List<T>.forEachSequentialPair(action: (T, T?) -> Unit) {
113 forEachIndexed { index, t ->
114 action(t, getOrNull(index + 1))
115 }
116 }
117
parseJavanull118 fun <T: Node> parseJava(fn: JavaParser.(String) -> ParseResult<T>, source: String): T = try {
119 val parse = JAVA_PARSER.fn(source)
120 if (parse.problems.isNotEmpty()) {
121 throw parseFailed(
122 source,
123 desc = parse.problems.joinToString("\n"),
124 cause = parse.problems.mapNotNull { it.cause.orElse(null) }.firstOrNull())
125 }
126 parse.result.get()
127 } catch (e: ParseProblemException) {
128 throw parseFailed(source, cause = e)
129 }
130
parseFailednull131 private fun parseFailed(source: String, cause: Throwable? = null, desc: String = ""): RuntimeException {
132 return RuntimeException("Failed to parse code:\n" +
133 source
134 .lines()
135 .mapIndexed { lnNum, ln -> "/*$lnNum*/$ln" }
136 .joinToString("\n") + "\n$desc",
137 cause)
138 }
139
140 var <T> MutableList<T>.last
141 get() = last()
142 set(value) {
143 if (isEmpty()) {
144 add(value)
145 } else {
146 this[size - 1] = value
147 }
148 }
149
buildListnull150 inline fun <T> buildList(init: MutableList<T>.() -> Unit) = mutableListOf<T>().apply(init)