"""
Methods for parsing standard JVM type descriptors for fields and methods.
"""
from collections import namedtuple
JVMType = namedtuple('JVMType', [
'base_type',
'dimensions',
'name'
])
MethodDescriptor = namedtuple('MethodDescriptor', [
'returns',
'args',
'returns_descriptor',
'args_descriptor',
'descriptor'
])
[docs]def method_descriptor(descriptor: str) -> MethodDescriptor:
"""
Parses a Method descriptor as described in section 4.3.3 of the JVM
specification.
"""
end_para = descriptor.find(')')
returns = descriptor[end_para + 1:]
args = descriptor[1:end_para]
return MethodDescriptor(
parse_descriptor(returns)[0],
parse_descriptor(args),
returns,
args,
descriptor
)
[docs]def field_descriptor(descriptor: str) -> str:
"""
Parses a Field descriptor as described in section 4.3.2 of the JVM
specification.
"""
return parse_descriptor(descriptor)[0]
# JVM Descriptor "BaseType" characters to their
# full simple type.
_HUMAN_NAMES = {
'L': 'reference',
'B': 'byte',
'C': 'char',
'D': 'double',
'F': 'float',
'I': 'int',
'J': 'long',
'S': 'short',
'Z': 'boolean',
'V': 'void'
}
[docs]def parse_descriptor(descriptor: str) -> list:
"""
Uses a tiny state machine to parse JVM descriptors. To get useful wrappers
around the results, use :py:func:`jawa.core.descriptor.method_descriptor`
or :py:func:`jawa.core.descriptor.field_descriptor`.
"""
# States:
# 10 == NORMAL,
# 20 == OBJECT REFERENCE
state = 10
tokens = []
token = []
dimensions = 0
for char in descriptor:
if state == 10 and char == 'L':
state = 20
elif state == 10 and char == '[':
dimensions += 1
elif state == 10:
tokens.append(JVMType(char, dimensions, _HUMAN_NAMES[char]))
dimensions = 0
elif state == 20 and char == ';':
tokens.append(JVMType('L', dimensions, ''.join(token)))
dimensions = 0
state = 10
del token[:]
elif state == 20:
token.append(char)
return tokens