aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/mcprepack/ParseMethodDescriptor.kt
blob: a3d57179e9c9f461c51cb00ff34c23f4d591098f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package mcprepack

import net.fabricmc.stitch.commands.tinyv2.TinyFile
import java.io.StringReader

sealed interface TypeDescriptor {
    fun mapClassName(tinyFile: TinyFile): TypeDescriptor {
        return when (this) {
            is Class ->
                Class(tinyFile.mapClassesByFirstNamespace()[this.name]?.classNames?.get(2) ?: this.name)

            else -> this
        }
    }

    fun toProguardString(): String {
        return when (this) {
            is Array -> this.elementType.toProguardString() + "[]"
            Boolean -> "boolean"
            Byte -> "byte"
            Char -> "char"
            is Class -> this.name.replace("/", ".")
            Double -> "double"
            Float -> "float"
            Int -> "int"
            Long -> "long"
            Short -> "short"
            Void -> "void"
        }
    }

    sealed interface FieldDescriptor : TypeDescriptor
    object Void : TypeDescriptor
    object Double : FieldDescriptor
    object Boolean : FieldDescriptor
    object Float : FieldDescriptor
    object Int : FieldDescriptor
    object Long : FieldDescriptor
    object Short : FieldDescriptor
    object Byte : FieldDescriptor
    object Char : FieldDescriptor
    data class Class(val name: String) : FieldDescriptor
    data class Array(val elementType: TypeDescriptor) : FieldDescriptor
}

data class FieldDescriptor(
    val type: TypeDescriptor.FieldDescriptor
) {
    companion object {
        fun parseFieldDescriptor(descriptor: String) =
            FieldDescriptor(readType(StringReader(descriptor)) as? TypeDescriptor.FieldDescriptor ?: error("Cannot have void as a field type"))
    }
}

data class MethodDescriptor(
    val arguments: List<TypeDescriptor.FieldDescriptor>,
    val returnType: TypeDescriptor
) {
    companion object {
        fun parseMethodDescriptor(descriptor: String): MethodDescriptor {
            val reader = StringReader(descriptor)
            require(reader.readChar() == '(')
            val arguments = mutableListOf<TypeDescriptor.FieldDescriptor>()
            while (reader.peek() != ')') {
                arguments.add(
                    readType(reader) as? TypeDescriptor.FieldDescriptor ?: error("Cannot have void type as argument")
                )
            }
            reader.readChar() // Consume the ')'
            return MethodDescriptor(arguments, readType(reader))
        }
    }
}

fun StringReader.readChar() = CharArray(1).let {
    if (read(it) < 0) null
    else it[0]
}

fun StringReader.readUntil(search: Char): String? {
    val s = StringBuilder()
    while (true) {
        val justRead = readChar() ?: return null
        if (justRead == search) return s.toString()
        s.append(justRead)
    }
}

fun StringReader.peek(): Char? {
    mark(0)
    val x = readChar()
    reset()
    return x
}


fun readType(reader: StringReader): TypeDescriptor {
    return when (reader.readChar()) {
        'L' -> TypeDescriptor.Class(reader.readUntil(';') ?: error("Unfinished class type descriptor"))
        'V' -> TypeDescriptor.Void
        'Z' -> TypeDescriptor.Boolean
        'B' -> TypeDescriptor.Byte
        'I' -> TypeDescriptor.Int
        'D' -> TypeDescriptor.Double
        'J' -> TypeDescriptor.Long
        'S' -> TypeDescriptor.Short
        'F' -> TypeDescriptor.Float
        'C' -> TypeDescriptor.Char
        '[' -> TypeDescriptor.Array(readType(reader))
        else -> error("Unknown or unfinished type descriptor")
    }
}