Skip to content
Permalink
Browse files

8244244: Better representing typedef in jextract API

Reviewed-by: mcimadamore, sundar
  • Loading branch information
slowhog committed May 1, 2020
1 parent 629afd9 commit 067ccd785fbf686754ffd70b21af1d8bf69ac4a1
@@ -164,10 +164,6 @@
* Bitfields declaration.
*/
BITFIELDS,
/**
* Type definition declaration.
*/
TYPEDEF,
/**
* Toplevel declaration.
*/
@@ -197,6 +193,17 @@
Kind kind();
}

/**
* A typedef declaration
*/
interface Typedef extends Declaration {
/**
* The canonical type associated with this typedef declaration.
* @return The canonical type associated with this typedef declaration.
*/
Type type();
}

/**
* A variable declaration.
*/
@@ -297,6 +304,14 @@
*/
default R visitConstant(Constant d, P p) { return visitDeclaration(d, p); }

/**
* Visit a typedef declaration.
* @param d the typedef declaration.
* @param p the visitor parameter.
* @return the result of visiting the given typedef declaration through this visitor object.
*/
default R visitTypedef(Typedef d, P p) { return visitDeclaration(d, p); }

/**
* Visit a declaration.
* @param d the declaration.
@@ -516,10 +531,10 @@
* Creates a new typedef declaration with given name and declared type.
* @param pos the typedef declaration position.
* @param name the typedef declaration name.
* @param decl the typedef declared type
* @return a new typedef declaration with given name and declared type.
* @param type the typedef type
* @return a new type declaration with given name and declared type.
*/
static Declaration.Scoped typedef(Position pos, String name, Declaration decl) {
return new DeclarationImpl.ScopedImpl(Scoped.Kind.TYPEDEF, List.of(decl), name, pos);
static Declaration.Typedef typedef(Position pos, String name, Type type) {
return new DeclarationImpl.TypedefImpl(type, name, pos, null);
}
}
@@ -218,9 +218,6 @@ public Void visitConstant(Declaration.Constant constant, Declaration parent) {

@Override
public Void visitScoped(Declaration.Scoped d, Declaration parent) {
if (d.kind() == Declaration.Scoped.Kind.TYPEDEF) {
return d.members().get(0).accept(this, d);
}
if (d.layout().isEmpty()) {
//skip decl-only
return null;
@@ -307,6 +304,20 @@ public Void visitFunction(Declaration.Function funcTree, Declaration parent) {
}
}

@Override
public Void visitTypedef(Declaration.Typedef tree, Declaration parent) {
Type type = tree.type();
if (type instanceof Type.Declared) {
Declaration.Scoped s = ((Type.Declared) type).tree();
// only generate unnamed for now
// skip typedef with different name
if (s.name().isEmpty()) {
return visitScoped(s, tree);
}
}
return null;
}

@Override
public Void visitVariable(Declaration.Variable tree, Declaration parent) {
if (parent == null && variableSeen(tree)) {
@@ -339,8 +350,7 @@ public Void visitVariable(Declaration.Variable tree, Declaration parent) {

MemoryLayout treeLayout = tree.layout().orElseThrow();
if (parent != null) { //struct field
Declaration.Scoped parentC = (Declaration.Scoped) parent;
MemoryLayout parentLayout = parentLayout(parentC);
MemoryLayout parentLayout = parentLayout(parent);
structBuilder.addVarHandleGetter(fieldName, tree.name(), treeLayout, clazz, parentLayout);
structBuilder.addGetter(fieldName, tree.name(), treeLayout, clazz, parentLayout);
structBuilder.addSetter(fieldName, tree.name(), treeLayout, clazz, parentLayout);
@@ -368,10 +378,15 @@ private boolean isRecord(Declaration declaration) {
}
}

protected static MemoryLayout parentLayout(Declaration.Scoped parent) {
protected static MemoryLayout parentLayout(Declaration parent) {
if (parent instanceof Declaration.Typedef) {
Declaration.Typedef alias = (Declaration.Typedef) parent;
return Type.layoutFor(alias.type()).orElseThrow();
} else if (parent instanceof Declaration.Scoped) {
return ((Declaration.Scoped) parent).layout().orElseThrow();
} else {
throw new IllegalArgumentException("Unexpected parent declaration");
}
// case like `typedef struct { ... } Foo`
return (parent.kind() == Declaration.Scoped.Kind.TYPEDEF
? (Declaration.Scoped) parent.members().get(0)
: parent).layout().orElseThrow();
}
}
@@ -99,6 +99,50 @@ public int hashCode() {
return Objects.hash(name);
}

public static final class TypedefImpl extends DeclarationImpl implements Declaration.Typedef {
final Type type;

public TypedefImpl(Type type, String name, Position pos, Map<String, List<Constable>> attrs) {
super(name, pos, attrs);
this.type = Objects.requireNonNull(type);
}

@Override
public <R, D> R accept(Visitor<R, D> visitor, D data) {
return visitor.visitTypedef(this, data);
}

@Override
public Type type() {
return type;
}

@Override
public Typedef withAttributes(Map<String, List<Constable>> attrs) {
return new TypedefImpl(type, name(), pos(), attrs);
}

@Override
public Typedef stripAttributes() {
return new TypedefImpl(type, name(), pos(), null);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Declaration.Typedef)) return false;

Declaration.Typedef other = (Declaration.Typedef) o;
return name().equals(other.name()) &&
type.equals(other.type());
}

@Override
public int hashCode() {
return Objects.hash(super.hashCode(), type);
}
}

public static final class VariableImpl extends DeclarationImpl implements Declaration.Variable {

final Variable.Kind kind;
@@ -154,8 +198,9 @@ public Variable stripAttributes() {
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Declaration.Variable)) return false;
if (!super.equals(o)) return false;

Declaration.Variable variable = (Declaration.Variable) o;
if (!super.equals(o)) return false;
return kind == variable.kind() &&
type.equals(variable.type());
}
@@ -49,7 +49,7 @@ void decr() {
void indent() {
builder.append(" ".substring(0, align));
}

StringBuilder builder = new StringBuilder();

private void getAttributes(Declaration decl) {
@@ -118,6 +118,15 @@ public Void visitConstant(Declaration.Constant d, Void aVoid) {
return null;
}

@Override
public Void visitTypedef(Declaration.Typedef d, Void aVoid) {
indent();
builder.append("Typedef: ").append(d.name()).append(" = ")
.append(d.type().accept(typeVisitor, null)).append("\n");
getAttributes(d);
return null;
}

private static Type.Visitor<String, Void> typeVisitor = new Type.Visitor<>() {
@Override
public String visitPrimitive(Type.Primitive t, Void aVoid) {
@@ -250,15 +250,17 @@ private static boolean isEnum(Declaration d) {
.collect(Collectors.toList());
}

private Declaration.Scoped createTypedef(Cursor c) {
Optional<Cursor> decl = c.children().findFirst();
if (decl.isPresent() && decl.get().isDefinition() && decl.get().spelling().isEmpty()) {
Declaration def = createTree(decl.get());
if (def instanceof Declaration.Scoped) {
return Declaration.typedef(toPos(c), c.spelling(), def);
private Declaration.Typedef createTypedef(Cursor c) {
Type.Delegated typedef = (Type.Delegated) toType(c);
Type canonicalType = typedef.type();
if (canonicalType instanceof Type.Declared) {
Declaration.Scoped s = ((Type.Declared) canonicalType).tree();
if (s.name().equals(c.spelling())) {
// typedef record with the same name, no need to present twice
return null;
}
}
return null;
return Declaration.typedef(toPos(c), c.spelling(), canonicalType);
}

private Declaration.Variable createVar(Declaration.Variable.Kind kind, Cursor c, VarFactoryNoLayout varFactory) {
@@ -23,8 +23,11 @@

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;

import jdk.incubator.jextract.Declaration;
import jdk.incubator.jextract.JextractTask;
import jdk.incubator.jextract.Type;
@@ -46,13 +49,44 @@
return task.parse(parseOptions);
}

public static void checkNames(List<Declaration> members, String... fields) {
assertEquals(members.size(), fields.length);
for (int i = 0; i < fields.length; i++) {
assertEquals(members.get(i).name(), fields[i]);
}
}

public static Declaration.Scoped checkScoped(Declaration.Scoped toplevel, String name, Declaration.Scoped.Kind kind, String... fields) {
Declaration.Scoped scoped = findDecl(toplevel, name, Declaration.Scoped.class);
assertEquals(scoped.members().size(), fields.length);
assertTrue(scoped.kind() == kind);
for (int i = 0; i < fields.length; i++) {
assertEquals(scoped.members().get(i).name(), fields[i]);
}
checkNames(scoped.members(), fields);
return scoped;
}

private static List<Declaration> getNamedFields(Declaration.Scoped scoped) {
List<Declaration> fields = new ArrayList<>();
scoped.members().forEach(d -> {
if (d instanceof Declaration.Variable) {
Declaration.Variable v = (Declaration.Variable) d;
if (v.kind() == Declaration.Variable.Kind.FIELD) {
assert (!v.name().isEmpty());
fields.add(v);
}
} else if (d instanceof Declaration.Scoped) {
Declaration.Scoped record = (Declaration.Scoped) d;
if (record.name().isEmpty()) {
fields.addAll(getNamedFields(record));
} else {
fields.add(record);
}
}
});
return fields;
}

public static Declaration.Scoped checkRecord(Declaration.Scoped scoped, String name, Declaration.Scoped.Kind kind, String... fields) {
assertTrue(scoped.kind() == kind);
checkNames(getNamedFields(scoped), fields);
return scoped;
}

@@ -68,26 +102,26 @@
return checkScoped(toplevel, name, Declaration.Scoped.Kind.UNION, fields);
}

public static Declaration.Variable checkConstant(Declaration.Scoped scope, String name, Type type) {
public static Declaration.Variable checkVariable(Declaration.Scoped scope, String name, Type type) {
Declaration.Variable var = findDecl(scope, name, Declaration.Variable.class);
assertTypeEquals(type, var.type());
return var;
}

public static Declaration.Variable checkGlobal(Declaration.Scoped toplevel, String name, Type type) {
Declaration.Variable global = checkConstant(toplevel, name, type);
Declaration.Variable global = checkVariable(toplevel, name, type);
assertEquals(global.kind(), Declaration.Variable.Kind.GLOBAL);
return global;
}

public static Declaration.Variable checkField(Declaration.Scoped record, String name, Type type) {
Declaration.Variable global = checkConstant(record, name, type);
Declaration.Variable global = checkVariable(record, name, type);
assertEquals(global.kind(), Declaration.Variable.Kind.FIELD);
return global;
}

public static Declaration.Variable checkBitField(Declaration.Scoped record, String name, Type type, int size) {
Declaration.Variable global = checkConstant(record, name, type);
Declaration.Variable global = checkVariable(record, name, type);
assertEquals(global.kind(), Declaration.Variable.Kind.BITFIELD);
assertEquals(global.layout().get().bitSize(), size);
return global;
@@ -165,4 +199,72 @@ public static void assertTypeEquals(Type expected, Type found) {
}
}
}

public static Type unwrapDelegatedType(Type type, Type.Delegated.Kind kind) {
assertTrue(type instanceof Type.Delegated,
"Expecting Type.Delegated, got " + type.getClass());
Type.Delegated delegated = (Type.Delegated) type;
assertEquals(delegated.kind(), kind);
return delegated.type();
}

public static Type unwrapPointerType(Type type) {
return unwrapDelegatedType(type, Type.Delegated.Kind.POINTER);
}

public static Type unwrapTypedefType(Type type) {
return unwrapDelegatedType(type, Type.Delegated.Kind.TYPEDEF);
}

public static Type unwrapArrayType(Type type, long size) {
assertTrue(type instanceof Type.Array,
"Expecting Type.Array, got " + type.getClass());
Type.Array arType = (Type.Array) type;
assertEquals(arType.elementCount().getAsLong(), size);
return arType.elementType();
}

public static Type unwrapArrayType(Type type) {
assertTrue(type instanceof Type.Array,
"Expecting Type.Array, got " + type.getClass());
Type.Array arType = (Type.Array) type;
assertTrue(arType.elementCount().isEmpty());
return arType.elementType();
}

static class TypeUnwrapper {
private Type type;

private TypeUnwrapper(Type type) {
this.type = type;
}

public static TypeUnwrapper of(Type type) {
return new TypeUnwrapper(type);
}

public TypeUnwrapper unwrapPointer() {
type = unwrapPointerType(type);
return this;
}

public TypeUnwrapper unwrapTypedef() {
type = unwrapTypedefType(type);
return this;
}

public TypeUnwrapper unwrapArray(long size) {
type = unwrapArrayType(type, size);
return this;
}

public TypeUnwrapper unwrapArray() {
type = unwrapArrayType(type);
return this;
}

public Type get() {
return type;
}
}
}

0 comments on commit 067ccd7

Please sign in to comment.
You can’t perform that action at this time.