Skip to content

Commit

Permalink
Fix method call (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
kaklakariada authored Oct 6, 2024
1 parent 5419af8 commit d7430cf
Show file tree
Hide file tree
Showing 10 changed files with 314 additions and 134 deletions.
101 changes: 48 additions & 53 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ repositories {
}

dependencies {
testImplementation libs.junit.jupiter
testImplementation libs.hamcrest
}

java {
Expand Down Expand Up @@ -48,58 +46,35 @@ sonarqube {

tasks.sonarqube.dependsOn([tasks.jacocoTestReport])

def currentOs = org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.currentOperatingSystem
testing {
suites {
test {
useJUnitJupiter(libs.versions.junit.jupiter)
dependencies {
implementation libs.hamcrest
implementation libs.mockito.core
implementation libs.mockito.junit
}
targets {
all {
testTask.configure {
systemProperty 'java.util.logging.config.file', 'src/test/resources/logging.properties'
systemProperty 'jextract.trace.downcalls', 'true'
environment "LD_LIBRARY_PATH", "${project.buildDir}/lua-libs/"
environment "DYLD_LIBRARY_PATH", "${project.buildDir}/lua-libs/"
//systemProperty 'jextract.trace.downcalls', 'true'
jvmArgs '--enable-native-access=ALL-UNNAMED'
if(currentOs.isMacOsX()) {
environment "DYLD_LIBRARY_PATH", "${project.buildDir}/lua-libs/"
}
if(currentOs.isLinux()) {
environment "LD_LIBRARY_PATH", "${project.buildDir}/lua-libs/"
}
}
}
}
}
}
}

def currentOs = org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.currentOperatingSystem
task downloadJextract(type: DownloadTask) {
def getOs = {
if(currentOs.isMacOsX()) {
return "macos"
}
if(currentOs.isLinux()) {
return "linux"
}
throw new IllegalStateException("Unsupported operating system: ${currentOs}")
}
def getArch = {
def arch = System.getProperty("os.arch")
switch(arch) {
case "amd64":
return "x64"
case "x86_64":
return "x64"
case "aarch64":
return "aarch64"
default:
throw new IllegalStateException("Unsupported architecture: ${arch}")
}
}
sourceUrl = "https://download.java.net/java/early_access/jextract/22/5/openjdk-22-jextract+5-33_${getOs()}-${getArch()}_bin.tar.gz"
target = file("${project.buildDir}/jextract.tar.gz")
}

task unpackJextract(type: Copy, dependsOn: [tasks.downloadJextract]) {
from tarTree(resources.gzip(tasks.downloadJextract.outputs.files[0]))
into file("${project.buildDir}/jextract/")
}

task buildLua(type: Exec) {
def getMakeGoal = {
if(currentOs.isLinux()) {
Expand Down Expand Up @@ -135,22 +110,42 @@ task cleanLua(type: Exec) {

clean.dependsOn(tasks.cleanLua)

task generateNativeInterface(type: Exec, dependsOn: [tasks.unpackJextract]) {
def jextractBinary = "${tasks.unpackJextract.outputs.files[0]}/jextract-22/bin/jextract"
def includeDir = "${project.rootDir}/lua/src"
def generatedSrc = "${project.buildDir}/generated/sources/jextract/"
commandLine jextractBinary,
'--include-dir', includeDir,
'--output', generatedSrc,
'--target-package', 'org.itsallcode.luava.ffi',
'--library', 'lua',
'--header-class-name', 'Lua',
"$includeDir/all_lua.h"
inputs.dir(includeDir)
outputs.dir(generatedSrc)
doLast {

task downloadJextract(type: DownloadTask) {
def getOs = {
if(currentOs.isMacOsX()) {
return "macos"
}
if(currentOs.isLinux()) {
return "linux"
}
throw new IllegalStateException("Unsupported operating system: ${currentOs}")
}
def getArch = {
def arch = System.getProperty("os.arch")
switch(arch) {
case "amd64":
return "x64"
case "x86_64":
return "x64"
case "aarch64":
return "aarch64"
default:
throw new IllegalStateException("Unsupported architecture: ${arch}")
}
}
sourceUrl = "https://download.java.net/java/early_access/jextract/22/5/openjdk-22-jextract+5-33_${getOs()}-${getArch()}_bin.tar.gz"
target = file("${project.buildDir}/jextract.tar.gz")
}

task unpackJextract(type: Copy, dependsOn: [tasks.downloadJextract]) {
from tarTree(resources.gzip(tasks.downloadJextract.outputs.files[0]))
into file("${project.buildDir}/jextract/")
}

task generateNativeInterface(type: JextractTask, dependsOn: [tasks.unpackJextract]) {
jextractBinary = new File(tasks.unpackJextract.outputs.files[0], "jextract-22/bin/jextract")
includeDir = new File(project.rootDir, "lua/src")
outputDir = new File(project.buildDir, "generated/sources/jextract/")
}

compileJava {
Expand Down
37 changes: 37 additions & 0 deletions buildSrc/src/main/groovy/JextractTask.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.CacheableTask
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity

@CacheableTask
class JextractTask extends DefaultTask {
@InputFile @PathSensitive(PathSensitivity.RELATIVE) File jextractBinary

@InputDirectory @PathSensitive(PathSensitivity.RELATIVE) File includeDir

@OutputDirectory File outputDir

@TaskAction
void generate() {
logger.info("Generating using binary ${jextractBinary} from ${includeDir} to ${outputDir}...")
def arguments = [
'--include-dir', includeDir,
'--output', outputDir,
'--target-package', 'org.itsallcode.luava.ffi',
'--library', 'lua',
'--header-class-name', 'Lua',
"$includeDir/all_lua.h"
]
project.exec {
workingDir project.rootDir
executable jextractBinary
args arguments
}
}
}
5 changes: 4 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
[versions]
junit-jupiter = "5.11.0"
junit-jupiter = "5.11.2"
hamcrest = "3.0"
mockito = "5.14.1"

[libraries]
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit-jupiter" }
hamcrest = { module = "org.hamcrest:hamcrest", version.ref = "hamcrest" }
mockito-core = { module = "org.mockito:mockito-core", version.ref = "mockito" }
mockito-junit = { module = "org.mockito:mockito-junit-jupiter", version.ref = "mockito" }
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
4 changes: 0 additions & 4 deletions src/main/java/org/itsallcode/luava/LowLevelLua.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,6 @@ LuaTable table(final int idx) {
return new LuaTable(state, stack, arena, idx);
}

public LuaFunction globalFunction(final String name) {
return new LuaFunction(this, name);
}

private void assertType(final int idx, final LuaType expectedType) {
final LuaType type = stack().getType(idx);
if (type != expectedType) {
Expand Down
45 changes: 5 additions & 40 deletions src/main/java/org/itsallcode/luava/LuaFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,15 @@

import static java.util.Collections.emptyList;

import java.lang.foreign.MemorySegment;
import java.util.Arrays;
import java.util.List;
import java.util.function.UnaryOperator;
import java.util.logging.Logger;

import org.itsallcode.luava.ffi.Lua;
import org.itsallcode.luava.ffi.lua_CFunction;

public class LuaFunction {
private static final Logger LOG = Logger.getLogger(LuaFunction.class.getName());
private static final int DEFAULT_MESSAGE_HANDLER = 0;
private final LowLevelLua lua;
private final String name;
private lua_CFunction.Function messageHandler;
private List<Object> argumentValues = emptyList();
private List<Class<?>> resultTypes = emptyList();

Expand All @@ -36,35 +31,13 @@ public LuaFunction resultTypes(final Class<?>... resultTypes) {
return this;
}

public LuaFunction messageUpdateHandler(final UnaryOperator<String> messageHandler) {
return messageHandler((final MemorySegment l) -> {
LOG.fine("Message handler: popping error message...");
final String msg = lua.stack().popString();
final String updatedMsg = messageHandler.apply(msg);
LOG.fine(() -> "Pushing updated error message '" + updatedMsg + "'");
lua.stack().pushString(updatedMsg);
return Lua.LUA_OK();
});
}

public LuaFunction messageHandler(final lua_CFunction.Function messageHandler) {
this.messageHandler = messageHandler;
return this;
}

public List<Object> call() {
final int messageHandlerIdx = getMessageHandlerIdx();
LOG.finest(() -> "Calling Lua function '" + name + "' with " + argumentValues.size() + " arguments and "
+ resultTypes.size() + " return values");
lua.getGlobal(name);
pushArguments();
try {
lua.pcall(this.argumentValues.size(), this.resultTypes.size(), messageHandlerIdx);
return getResultValues();
} finally {
if (this.messageHandler != null) {
LOG.fine("Popping message handler");
lua.stack().pop();
}
}
lua.pcall(this.argumentValues.size(), this.resultTypes.size(), DEFAULT_MESSAGE_HANDLER);
return getResultValues();
}

private void pushArguments() {
Expand All @@ -74,12 +47,4 @@ private void pushArguments() {
private List<Object> getResultValues() {
return this.resultTypes.stream().map(t -> lua.stack().popObject(t)).toList();
}

private int getMessageHandlerIdx() {
if (messageHandler == null) {
return 0;
}
lua.stack().pushCFunction(messageHandler);
return lua.stack().getTop();
}
}
36 changes: 35 additions & 1 deletion src/main/java/org/itsallcode/luava/LuaInterpreter.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
package org.itsallcode.luava;

import java.lang.foreign.MemorySegment;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.function.IntSupplier;

import org.itsallcode.luava.ffi.lua_CFunction;

public final class LuaInterpreter implements AutoCloseable {

private final LowLevelLua lua;
Expand Down Expand Up @@ -48,7 +55,7 @@ public LuaTable getGlobalTable(final String name) {
}

public LuaFunction getGlobalFunction(final String name) {
return lua.globalFunction(name);
return new LuaFunction(this.lua, name);
}

public void setGlobalString(final String name, final String value) {
Expand All @@ -71,6 +78,33 @@ public void setGlobalBoolean(final String name, final boolean value) {
lua.setGlobal(name);
}

public void setGlobalFunction(final String name, final Object object, final Method method) {
setGlobalFunction(name, () -> invokeMethod(object, method));
}

private int invokeMethod(final Object object, final Method method) {
final Object[] args = stack().getValues(method.getParameterTypes());
try {
final Object result = method.invoke(object, args);
if (method.getReturnType() != Void.class) {
stack().pushObject(result);
return 1;
}
return 0;
} catch (IllegalAccessException | InvocationTargetException e) {
throw new IllegalStateException("Failed to call Java method " + method + ": " + e.getMessage(), e);
}
}

private void setGlobalFunction(final String name, final IntSupplier fn) {
setGlobalFunction(name, (final MemorySegment l) -> fn.getAsInt());
}

private void setGlobalFunction(final String name, final lua_CFunction.Function fn) {
lua.stack().pushCFunction(fn);
lua.setGlobal(name);
}

public void exec(final String chunk) {
lua.loadString(chunk);
lua.pcall(0, 0);
Expand Down
Loading

0 comments on commit d7430cf

Please sign in to comment.