blob: b0bcf22bce5160cc0721e93e2b51ec7599350a69 [file] [log] [blame]
Alex Light630e4472020-09-08 14:41:09 -07001#!/usr/bin/python3
2#
3# Copyright 2020, The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16"""Converts a method to a descriptor or vice-versa.
17
18eg:
19
20% echo 'void myclass.foobar(long, java.lang.Object)' | method-to-descriptor.py
21Lmyclass;->foobar(jLjaga/lang/Object;)V
22% echo 'Lmyclass;->foobar(j)V' | method2descriptor.py -r
23void myclass.foobar(long)
24"""
25
26import argparse
27import sys
28
29
30def GetStdinLineIter():
31 """reads from stdin"""
32 return map(str.strip, sys.stdin)
33
34
35def readDescriptor(s):
36 """Reads a single descriptor and returns the string starting at the point after the descriptor"""
37 if s[0] == "[":
38 inner, rest = readDescriptor(s[1:])
39 return "[" + inner, rest
40 elif s[0] == "L":
41 type_end = s.index(";")
42 return s[:type_end + 1], s[type_end + 1:]
43 else:
44 assert s[0] in {"B", "C", "D", "F", "I", "J", "S", "Z", "V"}, s[0]
45 return s[0], s[1:]
46
47
48# Descriptor to name for basic types
49TYPE_MAP = {
50 "V": "void",
51 "B": "byte",
52 "C": "char",
53 "D": "double",
54 "F": "float",
55 "I": "int",
56 "J": "long",
57 "S": "short",
58 "Z": "boolean"
59}
60
61# Name to descriptor
62DESC_MAP = dict((y, x) for x, y in TYPE_MAP.items())
63
64def TypeDescriptorToName(desc):
65 """Turn a single type descirptor into a name"""
66 if desc[0] == "[":
67 inner = TypeDescriptorToName(desc[1:])
68 return inner + "[]"
69 elif desc[0] == "L":
70 assert desc[-1] == ";", desc
71 return desc[1:-1].replace("/", ".")
72 else:
73 return TYPE_MAP[desc]
74
75def DescriptorToName(desc):
76 """Turn a method descriptor into a name"""
77 class_name, rest = readDescriptor(desc)
78 assert rest[0:2] == "->", desc
79 rest = rest[2:]
80 args_start = rest.index("(")
81 func_name = rest[:args_start]
82 rest = rest[args_start + 1:]
83 args = []
84 while rest[0] != ")":
85 cur_arg, rest = readDescriptor(rest)
86 args.append(cur_arg)
87 rest = rest[1:]
88 return_type, rest = readDescriptor(rest)
89 assert rest.strip() == "", desc
90 return "{} {}.{}({})".format(
91 TypeDescriptorToName(return_type), TypeDescriptorToName(class_name),
92 func_name, ",".join(map(TypeDescriptorToName, args)))
93
94def SingleNameToDescriptor(name):
95 if name in DESC_MAP:
96 return DESC_MAP[name]
97 elif name.endswith("[]"):
98 return "[" + SingleNameToDescriptor(name[:-2])
99 elif name == "":
100 return ""
101 else:
102 return "L" + name.replace(".", "/") + ";"
103
104
105def NameToDescriptor(desc):
106 return_name = desc.split()[0]
107 name_and_args = desc.split()[1]
108 args_start = name_and_args.index("(")
109 names = name_and_args[0:args_start]
110 meth_split = names.rfind(".")
111 class_name = names[:meth_split]
112 meth_name = names[meth_split + 1:]
113 args = map(str.strip, name_and_args[args_start + 1:-1].split(","))
114 return "{}->{}({}){}".format(
115 SingleNameToDescriptor(class_name), meth_name,
116 "".join(map(SingleNameToDescriptor, args)),
117 SingleNameToDescriptor(return_name))
118
119
120def main():
121 parser = argparse.ArgumentParser(
122 "method-to-descriptor.py",
123 description="Convert a java method-name/stream into it's descriptor or vice-versa."
124 )
125 parser.add_argument(
126 "-r",
127 "--reverse",
128 dest="reverse",
129 action="store_true",
130 default=False,
131 help="reverse. Go from descriptor to method-declaration")
132 parser.add_argument("method", help="what to change", nargs="*")
133 args = parser.parse_args()
134 if args.method != []:
135 inputs = iter(args.method)
136 else:
137 inputs = GetStdinLineIter()
138 for name in inputs:
139 if args.reverse:
140 print(DescriptorToName(name))
141 else:
142 print(NameToDescriptor(name))
143
144
145if __name__ == "__main__":
146 main()