Skip to content

Commit

Permalink
Set trailing flag parameters as varargs (fixes #140)
Browse files Browse the repository at this point in the history
  • Loading branch information
jwharm committed Sep 28, 2024
1 parent 2e85680 commit f8da5c8
Show file tree
Hide file tree
Showing 21 changed files with 232 additions and 350 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.lang.model.element.Modifier;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.ValueLayout;
import java.util.*;

import static io.github.jwharm.javagi.util.Conversions.getValueLayout;
import static io.github.jwharm.javagi.util.Conversions.toJavaIdentifier;
import static java.util.function.Predicate.not;
import static java.util.stream.Collectors.joining;

Expand Down Expand Up @@ -97,8 +97,7 @@ String generateValueLayout(AnyType anyType) {
}

void generateMethodParameters(MethodSpec.Builder builder,
boolean generic,
boolean setOfBitfield) {
boolean generic) {
if (callable.parameters() == null)
return;

Expand All @@ -111,9 +110,19 @@ void generateMethodParameters(MethodSpec.Builder builder,
if (p.varargs()) {
builder.addParameter(Object[].class, "varargs");
builder.varargs(true);
} else if ((! (callable instanceof Callback))
&& (! (callable instanceof Signal))
&& (! p.isOutParameter())
&& p.isBitfield()
&& p.isLastParameter()) {
// Change trailing flags parameter into varargs
var name = toJavaIdentifier(p.name());
var type = p.anyType().typeName();
builder.addParameter(ArrayTypeName.of(type), name);
builder.varargs(true);
} else {
var generator = new TypedValueGenerator(p);
var type = generator.getType(setOfBitfield);
var type = generator.getType();

if (generic && type.equals(ClassNames.GOBJECT))
type = ClassNames.GENERIC_T;
Expand Down Expand Up @@ -222,90 +231,4 @@ boolean varargs() {
return params != null
&& params.parameters().stream().anyMatch(Parameter::varargs);
}

public MethodSpec generateBitfieldOverload() {
// Check if this is a (named) constructor
boolean ctor = callable instanceof Constructor;
boolean namedCtor = ctor && (!callable.name().equals("new"));

boolean generic = MethodGenerator.isGeneric(callable);

// Method name
String name = ctor
? ConstructorGenerator.getName((Constructor) callable, false)
: MethodGenerator.getName(callable);

MethodSpec.Builder builder;
if (ctor && (!namedCtor))
builder = MethodSpec.constructorBuilder();
else
builder = MethodSpec.methodBuilder(name);

// Javadoc
if (callable.infoElements().doc() != null) {
String doc = new DocGenerator(callable.infoElements().doc()).generate();
if (callable instanceof Multiplatform mp && mp.doPlatformCheck())
builder.addException(ClassNames.UNSUPPORTED_PLATFORM_EXCEPTION)
.addJavadoc(doc, ClassNames.UNSUPPORTED_PLATFORM_EXCEPTION);
else
builder.addJavadoc(doc);
}

// Deprecated annotation
if (callable.callableAttrs().deprecated())
builder.addAnnotation(Deprecated.class);

// Modifiers
builder.addModifiers(Modifier.PUBLIC);
if (callable instanceof Function || namedCtor)
builder.addModifiers(Modifier.STATIC);
else if (callable.parent() instanceof Interface)
builder.addModifiers(Modifier.DEFAULT);

// Return type
var returnValue = callable.returnValue();
if (generic && returnValue.anyType().typeName().equals(ClassNames.GOBJECT))
builder.returns(ClassNames.GENERIC_T);
else if ((!ctor) || namedCtor)
builder.returns(new TypedValueGenerator(returnValue).getType());

// Parameters
generateMethodParameters(builder, generic, false);

// Exception
if (callable.callableAttrs().throws_())
builder.addException(ClassNames.GERROR_EXCEPTION);

// Call the overloaded method
PartialStatement stmt = PartialStatement.of("");
if (ctor && (!namedCtor))
stmt.add("this");
else
stmt.add((returnValue.anyType().isVoid() ? "" : "return ") + name);

// Set parameters
StringJoiner params = new StringJoiner(",$W", "(", ");\n");
for (Parameter p : callable.parameters().parameters()) {
if (p.isUserDataParameter()
|| p.isDestroyNotifyParameter()
|| p.isArrayLengthParameter())
continue;

TypedValueGenerator gen = new TypedValueGenerator(p);

if (p.isBitfield()) {
if (p.isOutParameter())
params.add(gen.getName() + " == null ? null : new $out:T($enumSet:T.of(" + gen.getName() + ".get()))");
else
params.add("$enumSet:T.of(" + gen.getName() + ")");
} else {
params.add(gen.getName());
}
}
stmt.add(params.toString(),
"out", ClassNames.OUT,
"enumSet", EnumSet.class);
builder.addNamedCode(stmt.format(), stmt.arguments());
return builder.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import java.lang.invoke.MethodHandles;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Set;

import static io.github.jwharm.javagi.util.Conversions.*;
import static java.util.Comparator.comparing;
Expand Down Expand Up @@ -93,7 +94,7 @@ MethodSpec generateRunMethod() {
if (closure.throws_())
run.addException(ClassNames.GERROR_EXCEPTION);

generator.generateMethodParameters(run, false, true);
generator.generateMethodParameters(run, false);
return run.build();
}

Expand Down Expand Up @@ -231,9 +232,10 @@ && getCarrierTypeName(returnValue.anyType(), false).equals(TypeName.get(MemorySe
if (methodToInvoke.endsWith("invoke")) {
upcall.nextControlFlow("catch ($T ite)",
InvocationTargetException.class);
upcall.addStatement("$T.log($T.LOG_DOMAIN, $T.LEVEL_WARNING, ite.getCause().toString() + $S + $L)",
upcall.addStatement("$T.log($T.LOG_DOMAIN, $T.of($T.LEVEL_WARNING), ite.getCause().toString() + $S + $L)",
ClassNames.GLIB,
ClassNames.CONSTANTS,
Set.class,
ClassNames.LOG_LEVEL_FLAGS,
" in ",
methodName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ private MethodSpec constructor() {
builder.addAnnotation(Deprecated.class);

// Parameters
new CallableGenerator(ctor).generateMethodParameters(builder, false, true);
new CallableGenerator(ctor).generateMethodParameters(builder, false);

// Exception
if (ctor.callableAttrs().throws_())
Expand Down Expand Up @@ -147,8 +147,7 @@ private MethodSpec namedConstructor() {
builder.addAnnotation(Deprecated.class);

// Parameters
new CallableGenerator(ctor)
.generateMethodParameters(builder, false, true);
new CallableGenerator(ctor).generateMethodParameters(builder, false);

// Exception
if (ctor.callableAttrs().throws_())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ else if (func instanceof Constructor)
builder.returns(new TypedValueGenerator(returnValue).getType());

// Parameters
generator.generateMethodParameters(builder, generic, true);
generator.generateMethodParameters(builder, generic);

// Exception
if (func.callableAttrs().throws_())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,8 @@ public TypeSpec generateGlobalsClass() {
}

for (Function f : ns.functions()) {
if (!f.skip()) {
if (!f.skip())
builder.addMethod(new MethodGenerator(f).generate());
if (f.hasBitfieldParameters())
builder.addMethod(new CallableGenerator(f)
.generateBitfieldOverload());
}
}

if (hasDowncallHandles())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,34 +75,22 @@ protected MethodSpec getTypeMethod() {

protected void addFunctions(TypeSpec.Builder builder) {
for (Function f : filter(rt.children(), Function.class)) {
if (!f.skip()) {
if (!f.skip())
builder.addMethod(new MethodGenerator(f).generate());
if (f.hasBitfieldParameters())
builder.addMethod(new CallableGenerator(f)
.generateBitfieldOverload());
}
}
}

protected void addConstructors(TypeSpec.Builder builder) {
for (Constructor c : filter(rt.children(), Constructor.class)) {
if (!c.skip()) {
if (!c.skip())
builder.addMethods(new ConstructorGenerator(c).generate());
if (c.hasBitfieldParameters())
builder.addMethod(new CallableGenerator(c)
.generateBitfieldOverload());
}
}
}

protected void addMethods(TypeSpec.Builder builder) {
for (Method m : filter(rt.children(), Method.class)) {
if (!m.skip()) {
if (!m.skip())
builder.addMethod(new MethodGenerator(m).generate());
if (m.hasBitfieldParameters())
builder.addMethod(new CallableGenerator(m)
.generateBitfieldOverload());
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ public MethodSpec generateEmitMethod() {
.build());

// Add method parameters
generator.generateMethodParameters(builder, false, true);
generator.generateMethodParameters(builder, false);

// Arena for memory allocations
builder.beginControlFlow("try ($1T _arena = $1T.ofConfined())",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,28 +84,23 @@ String doFree() {
}

TypeName getType() {
return getType(true);
}

TypeName getType(boolean setOfBitfield) {
if (type != null && type.isActuallyAnArray())
return ArrayTypeName.of(getType(type, setOfBitfield));
return ArrayTypeName.of(getType(type));

if (v instanceof Field f && f.callback() != null)
return f.parent().typeName().nestedClass(
toJavaSimpleType(f.name() + "_callback", f.namespace()));

try {
return getType(v.anyType(), setOfBitfield);
return getType(v.anyType());
} catch (NullPointerException npe) {
throw new NoSuchElementException("Cannot find " + type);
}
}

private TypeName getType(AnyType anyType, boolean setOfBitfield) {
// Wrap Bitfield return value into a Set<>
private TypeName getType(AnyType anyType) {
TypeName typeName = anyType.typeName();
typeName = (setOfBitfield && v.isBitfield())
typeName = (v.isBitfield())
? ParameterizedTypeName.get(ClassName.get(Set.class), typeName)
: typeName;

Expand Down Expand Up @@ -662,7 +657,7 @@ FieldSpec generateConstantDeclaration() {
final String value = ((Constant) v).value();
try {
var builder = FieldSpec.builder(
getType(true),
getType(),
toJavaConstant(v.name()),
Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ public boolean allocatesMemory() {
&& target instanceof Alias a && a.type().isPrimitive();
}

public boolean isLastParameter() {
return this == parent().parameters().getLast();
}

public boolean nullable() {
return "1".equals(attr("nullable"))
|| "1".equals(attr("allow-none"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
Expand All @@ -54,7 +55,7 @@ public void createFile() {

// write to file
input = "test string";
try (var stream = file.create(FileCreateFlags.REPLACE_DESTINATION, null)) {
try (var stream = file.create(Set.of(FileCreateFlags.REPLACE_DESTINATION), null)) {
stream.write(input.getBytes(StandardCharsets.UTF_8), null);
}

Expand Down
Loading

0 comments on commit f8da5c8

Please sign in to comment.