Skip to content

Commit

Permalink
Add support for more types
Browse files Browse the repository at this point in the history
Reviewed-by: psandoz
  • Loading branch information
mcimadamore committed Apr 26, 2024
1 parent 9f35792 commit 6713aca
Show file tree
Hide file tree
Showing 21 changed files with 811 additions and 191 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

package java.lang.reflect.code.parser.impl;

import java.lang.reflect.code.parser.impl.Tokens.Token;
import java.lang.reflect.code.parser.impl.Tokens.TokenKind;
import java.lang.reflect.code.type.*;
import java.lang.reflect.code.TypeElement;
import java.lang.reflect.code.type.RecordTypeRef;
Expand All @@ -33,6 +35,7 @@
import java.lang.reflect.code.type.impl.RecordTypeRefImpl;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public final class DescParser {
private DescParser() {}
Expand Down Expand Up @@ -85,14 +88,26 @@ public static RecordTypeRef parseRecordTypeRef(String desc) {
}

public static TypeDefinition parseTypeDefinition(Lexer l) {
// Type
Tokens.Token t = l.accept(Tokens.TokenKind.IDENTIFIER);
StringBuilder identifier = new StringBuilder();
identifier.append(t.name());
while (l.acceptIf(Tokens.TokenKind.DOT)) {
identifier.append(Tokens.TokenKind.DOT.name);
t = l.accept(Tokens.TokenKind.IDENTIFIER);
identifier.append(t.name());
if (l.token().kind == TokenKind.HASH) {
// Quoted identifier
l.accept(TokenKind.HASH);
Token t = l.token();
while (t.kind != TokenKind.LT) {
identifier.append(t.kind == TokenKind.IDENTIFIER ? t.name() : t.kind.name);
l.nextToken();
t = l.token();
}
} else {
// Qualified identifier
Tokens.Token t = l.accept(TokenKind.IDENTIFIER,
TokenKind.PLUS, TokenKind.SUB);
identifier.append(t.kind == TokenKind.IDENTIFIER ? t.name() : t.kind.name);
while (l.acceptIf(Tokens.TokenKind.DOT)) {
identifier.append(Tokens.TokenKind.DOT.name);
t = l.accept(Tokens.TokenKind.IDENTIFIER);
identifier.append(t.name());
}
}

// Type parameters
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

package java.lang.reflect.code.parser.impl;

import java.lang.reflect.code.parser.impl.Tokens.TokenKind;
import java.util.ArrayList;
import java.util.List;

Expand Down Expand Up @@ -860,6 +861,11 @@ public Tokens.Token readToken() {
tk = Tokens.TokenKind.GT;
break loop;

case '#':
next();
tk = TokenKind.HASH;
break loop;

case '+':
next();
tk = Tokens.TokenKind.PLUS;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
package java.lang.reflect.code.parser.impl;

import java.lang.reflect.code.parser.impl.Position.LineMap;
import java.lang.reflect.code.parser.impl.Tokens.Token;
import java.util.Arrays;

/**
* The lexical analyzer maps an input stream consisting of ASCII
Expand Down Expand Up @@ -99,6 +101,21 @@ default Tokens.Token accept(Tokens.TokenKind tk) {
}
}

default Tokens.Token accept(Tokens.TokenKind... tks) {
Token t = token();
for (Tokens.TokenKind tk : tks) {
if (acceptIf(tk)) {
return t;
}
}
// @@@ Exception
LineMap lineMap = getLineMap();
int lineNumber = lineMap.getLineNumber(t.pos);
int columnNumber = lineMap.getColumnNumber(t.pos);
throw new IllegalArgumentException("Expected one of " + Arrays.toString(tks) + " but observed " + t.kind +
" " + lineNumber + ":" + columnNumber);
}

default boolean acceptIf(Tokens.TokenKind tk) {
Tokens.Token t = token();
if (t.kind == tk) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ public enum TokenKind implements Predicate<TokenKind> {
AMP("&"),
CARET("^"),
MONKEYS_AT("@"),
HASH("#"),
CUSTOM;

public final String name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ public int hashCode() {
return 17 * componentType.hashCode();
}

@Override
public JavaType erasure() {
return JavaType.array(componentType.erasure());
}

@Override
public JavaType toBasicType() {
return JavaType.J_L_OBJECT;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ public int hashCode() {
return result;
}

@Override
public JavaType erasure() {
return rawType();
}

@Override
public boolean isArray() {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.lang.constant.ClassDesc;
import java.lang.reflect.code.TypeElement;
import java.lang.reflect.code.type.WildcardType.BoundKind;
import java.util.ArrayList;
import java.util.List;

Expand Down Expand Up @@ -114,6 +115,29 @@ public TypeElement constructType(TypeDefinition tree) {
}
typeArguments.add(a);
}
if (identifier.equals("+") || identifier.equals("-")) {
// wildcard type
BoundKind kind = identifier.equals("+") ?
BoundKind.EXTENDS : BoundKind.SUPER;
return JavaType.wildcard(kind, typeArguments.get(0));
} else if (identifier.startsWith("#")) {
// type-var
if (typeArguments.size() != 1) {
throw new IllegalArgumentException("Bad type-variable bounds: " + tree);
}
String[] parts = identifier.split("::");
if (parts.length == 2) {
// class type-var
return JavaType.typeVarRef(parts[1],
(JavaType)constructType(parseTypeDef(parts[0])),
typeArguments.get(0));
} else {
// method type-var
return JavaType.typeVarRef(parts[2],
parseMethodRef(String.format("%s::%s", parts[0], parts[1])),
typeArguments.get(0));
}
}
JavaType t = switch (identifier) {
case "boolean" -> JavaType.BOOLEAN;
case "byte" -> JavaType.BYTE;
Expand Down Expand Up @@ -141,4 +165,14 @@ public TypeElement constructType(TypeDefinition tree) {
* may contain instances of those types.
*/
public static final TypeElementFactory CORE_TYPE_FACTORY = codeModelTypeFactory(JAVA_TYPE_FACTORY);

// Copied code in jdk.compiler module throws UOE
static MethodRef parseMethodRef(String desc) {
/*__throw new UnsupportedOperationException();__*/ return java.lang.reflect.code.parser.impl.DescParser.parseMethodRef(desc);
}

// Copied code in jdk.compiler module throws UOE
static TypeDefinition parseTypeDef(String desc) {
/*__throw new UnsupportedOperationException();__*/ return java.lang.reflect.code.parser.impl.DescParser.parseTypeDefinition(desc);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.lang.constant.ClassDesc;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.code.TypeElement;
import java.lang.reflect.code.type.WildcardType.BoundKind;
import java.util.List;
import java.util.Map;
import java.util.Objects;
Expand All @@ -36,7 +37,8 @@
* The symbolic description of a Java type.
*/
// @@@ Extend from this interface to model Java types with more fidelity
public sealed interface JavaType extends TypeElement permits ClassType, ArrayType, PrimitiveType {
public sealed interface JavaType extends TypeElement permits ClassType, ArrayType,
PrimitiveType, WildcardType, TypeVarRef {

// @@@ Share with general void type?
JavaType VOID = new PrimitiveType("void");
Expand Down Expand Up @@ -147,6 +149,11 @@ default Class<?> resolve(MethodHandles.Lookup l) throws ReflectiveOperationExcep

boolean isPrimitive();

/**
* {@return the erasure of this Java type, as per JLS 4.6}
*/
JavaType erasure();

// Factories

static JavaType type(Class<?> c) {
Expand Down Expand Up @@ -254,6 +261,46 @@ static ArrayType array(JavaType elementType, int dims) {
return array(elementType);
}

/**
* Constructs an unbounded wildcard type.
*
* @return an unbounded wildcard type.
*/
static WildcardType wildcard() {
return new WildcardType(BoundKind.EXTENDS, JavaType.J_L_OBJECT);
}

/**
* Constructs a bounded wildcard type of the given kind.
*
* @return a bounded wildcard type.
*/
static WildcardType wildcard(BoundKind kind, JavaType bound) {
return new WildcardType(kind, bound);
}

/**
* Constructs a reference to a class type-variable.
*
* @param bound the type-variable bound.
* @param owner the class where the type-variable is declared.
* @return a type-variable reference.
*/
static TypeVarRef typeVarRef(String name, JavaType owner, JavaType bound) {
return new TypeVarRef(name, owner, bound);
}

/**
* Constructs a reference to a method type-variable.
*
* @param bound the type-variable bound.
* @param owner the method where the type-variable is declared.
* @return a type-variable reference.
*/
static TypeVarRef typeVarRef(String name, MethodRef owner, JavaType bound) {
return new TypeVarRef(name, owner, bound);
}

// Copied code in jdk.compiler module throws UOE
static JavaType ofString(String s) {
/*__throw new UnsupportedOperationException();__*/ return (JavaType) CoreTypeFactory.JAVA_TYPE_FACTORY.constructType(java.lang.reflect.code.parser.impl.DescParser.parseTypeDefinition(s));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ public int hashCode() {
return type.hashCode();
}

@Override
public JavaType erasure() {
return this;
}

@Override
public boolean isArray() {
return false;
Expand Down
Loading

0 comments on commit 6713aca

Please sign in to comment.