
org.opalj.br.reader.SignatureParser.scala Maven / Gradle / Ivy
The newest version!
/* BSD 2-Clause License - see OPAL/LICENSE for details. */
package org.opalj
package br
package reader
import scala.util.parsing.combinator._
// IMPROVE consider making the signature parser abstract and use the factory pattern as in the case of all other major structures
/**
* Parses Java class file signature strings.
*
* ==Thread-Safety==
* Using this object is thread-safe.
*
* @author Michael Eichberg
*/
object SignatureParser {
/**
* Parses Java class file signature strings.
*
* ==Thread-Safety==
* As of Scala 2.10/2.11 classes that inherit from `(Regex)Parsers` are not thread-safe.
* However, the only class that can create instances of a `SignatureParsers` is
* its companion object and that one implements the necessary abstractions for the
* thread-safe use of `SignatureParsers`.
*/
class SignatureParsers private[SignatureParser] () extends RegexParsers {
def parseClassSignature(signature: String): ClassSignature = {
val cs = parseAll(classSignatureParser, signature)
if (cs.isEmpty)
throw new IllegalArgumentException("invalid class signature: "+signature)
else
cs.get
}
def parseFieldTypeSignature(signature: String): FieldTypeSignature = {
val fts = parseAll(fieldTypeSignatureParser, signature)
if (fts.isEmpty)
throw new IllegalArgumentException("invalid field type signature: "+signature)
else
fts.get
}
def parseMethodTypeSignature(signature: String): MethodTypeSignature = {
val mts = parseAll(methodTypeSignatureParser, signature)
if (mts.isEmpty)
throw new IllegalArgumentException("invalid method type signature: "+signature)
else
mts.get
}
//
// The methods to parse signatures.
//
protected val classSignatureParser: Parser[ClassSignature] =
opt(formalTypeParametersParser) ~
superclassSignatureParser ~
rep(superinterfaceSignatureParser) ^^ {
case ftps ~ scs ~ siss => ClassSignature(ftps.getOrElse(Nil), scs, siss)
}
protected val fieldTypeSignatureParser: Parser[FieldTypeSignature] =
classTypeSignatureParser |
typeVariableSignatureParser |
arrayTypeSignatureParser
protected val methodTypeSignatureParser: Parser[MethodTypeSignature] =
opt(formalTypeParametersParser) ~
('(' ~> rep(typeSignatureParser) <~ ')') ~
returnTypeParser ~
rep(throwsSignatureParser) ^^ {
case ftps ~ psts ~ rt ~ tss =>
MethodTypeSignature(ftps.getOrElse(Nil), psts, rt, tss)
}
protected val identifierParser: Parser[String] = """[^.;\[/\<>\:]*""".r
protected def formalTypeParametersParser: Parser[List[FormalTypeParameter]] =
'<' ~> rep1(formalTypeParameterParser) <~ '>'
protected def formalTypeParameterParser: Parser[FormalTypeParameter] =
identifierParser ~ classBoundParser ~ rep(interfaceBoundParser) ^^ {
case id ~ cb ~ ib => FormalTypeParameter(id, cb, ib)
}
protected def classBoundParser: Parser[Option[FieldTypeSignature]] =
':' ~> opt(fieldTypeSignatureParser)
protected def interfaceBoundParser: Parser[FieldTypeSignature] =
':' ~> fieldTypeSignatureParser
protected def superclassSignatureParser: Parser[ClassTypeSignature] =
classTypeSignatureParser
protected def superinterfaceSignatureParser: Parser[ClassTypeSignature] =
classTypeSignatureParser
/**
* '''From the JVM Specification'''
*
* A class type signature gives complete type information for a class or
* interface type. The class type signature must be formulated such that
* it can be reliably mapped to the binary name of the class it denotes
* by erasing any type arguments and converting each ‘.’ character in
* the signature to a ‘$’ character.
*/
protected def classTypeSignatureParser: Parser[ClassTypeSignature] =
'L' ~>
opt(packageSpecifierParser) ~
simpleClassTypeSignatureParser ~
rep(classTypeSignatureSuffixParser) <~ ';' ^^ {
case ps ~ scts ~ ctsss => ClassTypeSignature(ps, scts, ctsss)
}
protected def packageSpecifierParser: Parser[String] =
(identifierParser ~ ('/' ~> opt(packageSpecifierParser))) ^^ {
case id ~ rest => id + '/' + rest.getOrElse("")
}
protected def simpleClassTypeSignatureParser: Parser[SimpleClassTypeSignature] =
identifierParser ~ opt(typeArgumentsParser) ^^ {
case id ~ tas => SimpleClassTypeSignature(id, tas.getOrElse(Nil))
}
protected def classTypeSignatureSuffixParser: Parser[SimpleClassTypeSignature] =
'.' ~> simpleClassTypeSignatureParser
protected def typeVariableSignatureParser: Parser[TypeVariableSignature] =
('T' ~> identifierParser <~ ';') ^^ { TypeVariableSignature(_) }
protected def typeArgumentsParser: Parser[List[TypeArgument]] =
'<' ~> rep1(typeArgumentParser) <~ '>'
protected def typeArgumentParser: Parser[TypeArgument] =
(opt(wildcardIndicatorParser) ~ fieldTypeSignatureParser) ^^ {
case wi ~ fts => ProperTypeArgument(wi, fts)
} |
('*' ^^^ { Wildcard })
protected def wildcardIndicatorParser: Parser[VarianceIndicator] =
// Conceptually, we do the following:
// '+' ^^ { _ => CovariantIndicator } | '-' ^^ { _ => ContravariantIndicator }
new Parser[VarianceIndicator] {
def apply(in: Input): ParseResult[VarianceIndicator] = {
if (in.atEnd) Failure("signature incomplete", in)
else (in.first: @scala.annotation.switch) match {
case '+' => Success(CovariantIndicator, in.rest)
case '-' => Success(ContravariantIndicator, in.rest)
case x => Failure(s"unknown wildcard indicator: $x", in.rest)
}
}
}
protected def arrayTypeSignatureParser: Parser[ArrayTypeSignature] =
'[' ~> typeSignatureParser ^^ { ArrayTypeSignature(_) }
protected def typeSignatureParser: Parser[TypeSignature] =
fieldTypeSignatureParser | baseTypeParser
protected def throwsSignatureParser: Parser[ThrowsSignature] =
'^' ~> (classTypeSignatureParser | typeVariableSignatureParser)
protected def baseTypeParser: Parser[BaseType] =
// This is what is conceptually done:
// 'B' ^^ (_ => ByteType) | 'C' ^^ (_ => CharType) | 'D' ^^ (_ => DoubleType) |
// 'F' ^^ (_ => FloatType) | 'I' ^^ (_ => IntegerType) | 'J' ^^ (_ => LongType) |
// 'S' ^^ (_ => ShortType) | 'Z' ^^ (_ => BooleanType)
// This is a way more efficient implementation:
new Parser[BaseType] {
def apply(in: Input): ParseResult[BaseType] = {
if (in.atEnd) {
Failure("signature is incomplete, base type identifier expected", in)
} else {
(in.first: @scala.annotation.switch) match {
case 'B' => Success(ByteType, in.rest)
case 'C' => Success(CharType, in.rest)
case 'D' => Success(DoubleType, in.rest)
case 'F' => Success(FloatType, in.rest)
case 'I' => Success(IntegerType, in.rest)
case 'J' => Success(LongType, in.rest)
case 'S' => Success(ShortType, in.rest)
case 'Z' => Success(BooleanType, in.rest)
case x => Failure(s"unknown base type identifier: $x", in.rest)
}
}
}
}
protected def returnTypeParser: Parser[ReturnTypeSignature] =
typeSignatureParser | 'V' ^^^ { VoidType }
}
private def createSignatureParsers(): SignatureParsers = new SignatureParsers()
private val signatureParsers: ThreadLocal[SignatureParsers] =
new ThreadLocal[SignatureParsers] {
override protected def initialValue(): SignatureParsers = createSignatureParsers()
}
def parseClassSignature(signature: String): ClassSignature = {
signatureParsers.get.parseClassSignature(signature)
}
def parseFieldTypeSignature(signature: String): FieldTypeSignature = {
signatureParsers.get.parseFieldTypeSignature(signature)
}
def parseMethodTypeSignature(signature: String): MethodTypeSignature = {
signatureParsers.get.parseMethodTypeSignature(signature)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy