• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download

<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)