Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for more types #51

Closed
wants to merge 14 commits into from
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.lang.reflect.code.type.*;
import java.lang.reflect.code.TypeElement;
import java.lang.reflect.code.type.RecordTypeRef;
Expand Down Expand Up @@ -86,9 +87,17 @@ public static RecordTypeRef parseRecordTypeRef(String desc) {

public static TypeDefinition parseTypeDefinition(Lexer l) {
// Type
Tokens.Token t = l.accept(Tokens.TokenKind.IDENTIFIER);
Tokens.Token t = l.accept(TokenKind.IDENTIFIER,
TokenKind.PLUS, TokenKind.SUB,
TokenKind.AMP, TokenKind.OR,
TokenKind.COLCOL);
StringBuilder identifier = new StringBuilder();
identifier.append(t.name());
if (t.kind == TokenKind.COLCOL) {
// type var, add '::' and parse next ident
identifier.append(t.kind.name);
t = l.accept(TokenKind.IDENTIFIER);
}
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,11 @@ public Tokens.Token readToken() {
tk = Tokens.TokenKind.AMP;
break loop;

case '|':
next();
tk = Tokens.TokenKind.OR;
break loop;

case '@':
next();
tk = Tokens.TokenKind.MONKEYS_AT;
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 @@ -99,6 +99,7 @@ public enum TokenKind implements Predicate<TokenKind> {
PLUS("+"),
SUB("-"),
AMP("&"),
OR("|"),
CARET("^"),
MONKEYS_AT("@"),
CUSTOM;
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,21 @@ 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
return JavaType.typeVarRef(identifier.substring(2));
} else if (identifier.equals("&")) {
// intersection type
return JavaType.intersection(typeArguments);
} else if (identifier.equals("|")) {
// union type
return JavaType.union(typeArguments);
}
JavaType t = switch (identifier) {
case "boolean" -> JavaType.BOOLEAN;
case "byte" -> JavaType.BYTE;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

package java.lang.reflect.code.type;

import java.util.List;

/**
* An intersection type.
*/
public final class IntersectionType implements JavaType {

final List<JavaType> components;

IntersectionType(List<JavaType> components) {
this.components = components;
}

/**
* {@return the type-variable name}
*/
public List<JavaType> components() {
return components;
}

@Override
public TypeDefinition toTypeDefinition() {
return new TypeDefinition("&",
components.stream()
.map(JavaType::toTypeDefinition).toList());
}

@Override
public String toString() {
return toTypeDefinition().toString();
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
return o instanceof IntersectionType that &&
components.equals(that.components);
}

@Override
public int hashCode() {
return components.hashCode();
}

@Override
public JavaType toBasicType() {
throw new UnsupportedOperationException("Interesection type");
}

@Override
public String toNominalDescriptorString() {
throw new UnsupportedOperationException("Intersection type");
}

@Override
public boolean isClass() {
return false;
}

@Override
public boolean isArray() {
return false;
}

@Override
public boolean isPrimitive() {
return false;
}
}
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,9 @@
* 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,
IntersectionType, UnionType {

// @@@ Share with general void type?
JavaType VOID = new PrimitiveType("void");
Expand Down Expand Up @@ -254,6 +257,51 @@ 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 type-variable reference.
*
* @return a type-variable reference.
*/
static TypeVarRef typeVarRef(String name) {
return new TypeVarRef(name);
}

/**
* Constructs an intersection type with given components.
*
* @return an intersection type.
*/
static IntersectionType intersection(List<JavaType> components) {
return new IntersectionType(components);
}

/**
* Constructs a union type with given components.
*
* @return a union type.
*/
static UnionType union(List<JavaType> components) {
return new UnionType(components);
}

// 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
@@ -0,0 +1,95 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

package java.lang.reflect.code.type;

import java.util.List;

/**
* A type-variable reference.
*/
public final class TypeVarRef implements JavaType {

// @@@: how do we encode tvar owner?
Copy link
Collaborator Author

@mcimadamore mcimadamore Apr 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As the comment indicates, ideally a type-variable reference should also points to its owner (a type or a method). I'm not 100% sure how to encode that in the TypeElement structure (see also the toplevel PR summary).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now handled as part of 52fc6e9

final String name;

TypeVarRef(String name) {
this.name = name;
}

/**
* {@return the type-variable name}
*/
public String name() {
return name;
}

@Override
public TypeDefinition toTypeDefinition() {
return new TypeDefinition("::" + name, List.of());
}

@Override
public String toString() {
return toTypeDefinition().toString();
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
return o instanceof TypeVarRef that &&
name.equals(that.name);
}

@Override
public int hashCode() {
return name.hashCode();
}

@Override
public JavaType toBasicType() {
throw new UnsupportedOperationException("Type var");
}

@Override
public String toNominalDescriptorString() {
throw new UnsupportedOperationException("Type var");
}

@Override
public boolean isClass() {
return false;
}

@Override
public boolean isArray() {
return false;
}

@Override
public boolean isPrimitive() {
return false;
}
}
Loading