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

8244244: Better representing typedef in jextract API #137

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -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();
This conversation was marked as resolved by slowhog

This comment has been minimized.

@mcimadamore

mcimadamore May 1, 2020
Collaborator

No name?

}

/**
* 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);
}
}
@@ -217,9 +217,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;
}
}
}