Skip to content

Commit

Permalink
More gen code
Browse files Browse the repository at this point in the history
  • Loading branch information
xpenatan committed Jul 11, 2023
1 parent 590f305 commit dd6dd07
Show file tree
Hide file tree
Showing 13 changed files with 296 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.github.xpenatan.jparser.example.subpackage;

public class ParamClass {
}
5 changes: 5 additions & 0 deletions example/example-build/jni/cpp/src/NormalClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ NormalClass::NormalClass(ParamClass * pointerParamClass, ParamClass & refParamCl
d++;
}

int NormalClass::subIntValue(int a, int b)
{
return (a - b);
}

int NormalClass::addIntValue(int a, int b)
{
return (a + b) * hiddenInt * hiddenParentInt;
Expand Down
1 change: 1 addition & 0 deletions example/example-build/jni/cpp/src/NormalClass.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class NormalClass : public ParentClass
NormalClass(int c, ParamClass & refParamClass);
NormalClass(ParamClass * pointerParamClass, ParamClass & refParamClass, ParamClass valueParamClass);

static int subIntValue(int a, int b);
int addIntValue(int a, int b);
ReturnClass getReturnValueClass();
ReturnClass & getReturnRefClass();
Expand Down
5 changes: 3 additions & 2 deletions example/example-build/src/main/resources/idl/Test.idl
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ interface ParentClass {

interface NormalClass {
void NormalClass();
// void NormalClass(long c, [Ref]ParamClass refParamClass);
// void NormalClass(ParamClass pointerParamClass, [Ref]ParamClass refParamClass, [Value]ParamClass valueParamClass);
void NormalClass(long c, [Ref]ParamClass refParamClass);
void NormalClass(ParamClass pointerParamClass, [Ref]ParamClass refParamClass, [Value]ParamClass valueParamClass);

static long subIntValue(long a, long b);
long addIntValue(long a, long b);
// [Value]ReturnClass getReturnValueClass();
// [Ref]ReturnClass getReturnRefClass();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ public void test_add_int() {
assertEquals(20, ret);
}

@Test
public void test_static_sub_int() {
int ret = NormalClass.subIntValue(11, 10);
assertEquals(1, ret);
}

@Test
public void test_add_float() {
NormalClass normalClass = new NormalClass();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,11 @@ public static boolean containsImport(CompilationUnit unit, String fullyQualified
}

public static void addMissingImportType(JParser jParser, CompilationUnit unit, Type type) {
String s = type.asString();
JParserItem parserUnitItem = jParser.getParserUnitItem(s);
addMissingImportType(jParser, unit, type.asString());
}

public static void addMissingImportType(JParser jParser, CompilationUnit unit, String className) {
JParserItem parserUnitItem = jParser.getParserUnitItem(className);
if(parserUnitItem != null) {
ClassOrInterfaceDeclaration classDeclaration = parserUnitItem.getClassDeclaration();
if(classDeclaration != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,10 @@ public static void generateAttribute(IDLDefaultCodeParser idlParser, JParser jPa
getMethodDeclaration.setType(type);
JParserHelper.addMissingImportType(jParser, unit, type);
IDLDefaultCodeParser.setDefaultReturnValues(jParser, unit, type, getMethodDeclaration);
idlParser.onIDLMethodGenerated(jParser, idlClass, null, unit, classOrInterfaceDeclaration, getMethodDeclaration, true);

if(!idlParser.generateClass) {
idlParser.onIDLMethodGenerated(jParser, idlClass, null, unit, classOrInterfaceDeclaration, getMethodDeclaration, true);
}
}
if(addSet) {
if(setMethodDeclaration != null) {
Expand All @@ -101,7 +104,10 @@ public static void generateAttribute(IDLDefaultCodeParser idlParser, JParser jPa
Parameter parameter = setMethodDeclaration.addAndGetParameter(type, attributeName);
Type paramType = parameter.getType();
JParserHelper.addMissingImportType(jParser, unit, paramType);
idlParser.onIDLMethodGenerated(jParser, idlClass, null, unit, classOrInterfaceDeclaration, setMethodDeclaration, true);

if(!idlParser.generateClass) {
idlParser.onIDLMethodGenerated(jParser, idlClass, null, unit, classOrInterfaceDeclaration, setMethodDeclaration, true);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Modifier;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.ConstructorDeclaration;
import com.github.xpenatan.jparser.core.JParser;
import com.github.xpenatan.jparser.core.JParserItem;
import com.github.xpenatan.jparser.core.codeparser.DefaultCodeParser;
Expand Down Expand Up @@ -79,9 +80,14 @@ private CompilationUnit setupClass(IDLClass idlClass) {
classDeclaration.setPublic(true);

if(idlClass.classHeader.isNoDelete) {
// Class with no delete don't have constructor
classDeclaration.addConstructor(Modifier.Keyword.PROTECTED);
}

// All classes contain a temp constructor so temp objects can be created
ConstructorDeclaration constructorDeclaration = classDeclaration.addConstructor(Modifier.Keyword.PUBLIC);
constructorDeclaration.addParameter("byte", "temp");

return compilationUnit;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.ConstructorDeclaration;
import com.github.xpenatan.jparser.core.JParser;
import com.github.xpenatan.jparser.core.JParserHelper;
import com.github.xpenatan.jparser.idl.IDLClass;
import com.github.xpenatan.jparser.idl.IDLConstructor;
import com.github.xpenatan.jparser.idl.IDLParameter;
Expand All @@ -20,11 +21,17 @@ public static void generateConstructor(IDLDefaultCodeParser idlParser, JParser j
ArrayList<IDLParameter> parameters = idlConstructor.parameters;
for(int i = 0; i < parameters.size(); i++) {
IDLParameter parameter = parameters.get(i);
JParserHelper.addMissingImportType(jParser, unit, parameter.type);
constructorDeclaration.addAndGetParameter(parameter.type, parameter.name);
}
setupConstructor(jParser, idlConstructor, constructorDeclaration);
}
}

private static void setupConstructor(JParser jParser, IDLConstructor idlConstructor, ConstructorDeclaration constructorDeclaration) {

}

private static ConstructorDeclaration containsConstructor(ClassOrInterfaceDeclaration classOrInterfaceDeclaration, IDLConstructor idlConstructor) {
ArrayList<IDLParameter> parameters = idlConstructor.parameters;
String[] paramTypes = new String[parameters.size()];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public class IDLDefaultCodeParser extends IDLClassGeneratorParser {

protected boolean enableAttributeParsing = true;

static final String CPOINTER_METHOD = "getCPointer()";

public IDLDefaultCodeParser(String headerCMD, IDLReader idlReader) {
super("", headerCMD, idlReader);
}
Expand Down Expand Up @@ -104,7 +106,12 @@ else if(JParserHelper.isBoolean(returnType)) {
}
}

@Deprecated
public void onIDLMethodGenerated(JParser jParser, IDLClass idlClass, IDLMethod idlMethod, CompilationUnit unit, ClassOrInterfaceDeclaration classDeclaration, MethodDeclaration idlMethodDeclaration, boolean isAttribute) {
}


public void onIDLMethodGenerated(JParser jParser, IDLMethod idlMethod, ClassOrInterfaceDeclaration classDeclaration, MethodDeclaration methodDeclaration, MethodDeclaration nativeMethodDeclaration) {
}

}
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
package com.github.xpenatan.jparser.core.codeparser.idl;

import com.github.javaparser.Position;
import com.github.javaparser.Range;
import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Modifier;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.BodyDeclaration;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.InitializerDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.body.Parameter;
import com.github.javaparser.ast.comments.BlockComment;
import com.github.javaparser.ast.comments.Comment;
import com.github.javaparser.ast.expr.CastExpr;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.MethodCallExpr;
import com.github.javaparser.ast.expr.ObjectCreationExpr;
import com.github.javaparser.ast.stmt.BlockStmt;
import com.github.javaparser.ast.stmt.ReturnStmt;
import com.github.javaparser.ast.stmt.Statement;
import com.github.javaparser.ast.type.Type;
import com.github.xpenatan.jparser.core.JParser;
import com.github.xpenatan.jparser.core.JParserHelper;
Expand All @@ -22,6 +35,21 @@

public class IDLMethodParser {

static final String GET_OBJECT_TEMPLATE = "" +
"{\n" +
" long pointer = [METHOD];\n" +
" [TYPE]_TEMP_GEN_[NUM].setPointer(pointer);\n" +
" return [TYPE]_TEMP_GEN_[NUM];\n" +
"}";

static final String TEMPLATE_TEMP_FIELD = "[TYPE]_TEMP_GEN_[NUM]";

static final String TEMPLATE_TAG_METHOD = "[METHOD]";

static final String TEMPLATE_TAG_TYPE = "[TYPE]";

static final String TEMPLATE_TAG_NUM = "[NUM]";

public static void generateMethods(IDLDefaultCodeParser idlParser, JParser jParser, CompilationUnit unit, ClassOrInterfaceDeclaration classOrInterfaceDeclaration, IDLClass idlClass, IDLMethod idlMethod) {
if(idlMethod.skip) {
return;
Expand Down Expand Up @@ -80,7 +108,164 @@ public static void generateMethods(IDLDefaultCodeParser idlParser, JParser jPars
Type returnType = StaticJavaParser.parseType(idlMethod.returnType);
methodDeclaration.setType(returnType);
IDLDefaultCodeParser.setDefaultReturnValues(jParser, unit, returnType, methodDeclaration);
idlParser.onIDLMethodGenerated(jParser, idlClass, idlMethod, unit, classOrInterfaceDeclaration, methodDeclaration, false);

if(!idlParser.generateClass) {
idlParser.onIDLMethodGenerated(jParser, idlClass, idlMethod, unit, classOrInterfaceDeclaration, methodDeclaration, false);
}
else {
setupMethod(idlParser, jParser, idlMethod, classOrInterfaceDeclaration, methodDeclaration);
}
}

private static void setupMethod(IDLDefaultCodeParser idlParser, JParser jParser, IDLMethod idlMethod, ClassOrInterfaceDeclaration classDeclaration, MethodDeclaration methodDeclaration) {
MethodDeclaration nativeMethodDeclaration = generateNativeMethod(methodDeclaration);
if(!JParserHelper.containsMethod(classDeclaration, nativeMethodDeclaration)) {
//Add native method if it does not exist
classDeclaration.getMembers().add(nativeMethodDeclaration);
// Now that we have the native method we setup the caller method.

boolean isStatic = methodDeclaration.isStatic();
MethodCallExpr caller = new MethodCallExpr();
caller.setName(nativeMethodDeclaration.getNameAsString());
if(!isStatic) {
caller.addArgument(IDLDefaultCodeParser.CPOINTER_METHOD);
}

NodeList<Parameter> methodParameters = methodDeclaration.getParameters();
Type methodReturnType = methodDeclaration.getType();

for(int i = 0; i < methodParameters.size(); i++) {
Parameter parameter = methodParameters.get(i);
Type type = parameter.getType();
String paramName = parameter.getNameAsString();
if(type.isClassOrInterfaceType()) {
//All methods must contain a base class to get its pointer
String typeName = parameter.getType().toString();
paramName = paramName + ".getCPointer()";
}
caller.addArgument(paramName);
}

if(methodReturnType.isVoidType()) {
// void types just call the method.
BlockStmt blockStmt = methodDeclaration.getBody().get();
blockStmt.addStatement(caller);
}
else if(methodReturnType.isClassOrInterfaceType()) {
// Class object needs to generate some additional code.
// Needs to obtain the pointer and return a temp object.
BlockStmt blockStmt = generateTempObjects(classDeclaration, methodDeclaration, caller);
methodDeclaration.setBody(blockStmt);
}
else {
// Should be a primitive return type.
ReturnStmt returnStmt = getReturnStmt(methodDeclaration);
returnStmt.setExpression(caller);
}
idlParser.onIDLMethodGenerated(jParser, idlMethod, classDeclaration, methodDeclaration, nativeMethodDeclaration);
}
}

private static BlockStmt generateTempObjects(ClassOrInterfaceDeclaration classDeclaration, MethodDeclaration methodDeclaration, MethodCallExpr caller) {
// Will return a temp object.
// This variable will be created by checking its class, name and number.
// if the temp object already exist it will increment variable number and create it.

Type methodReturnType = methodDeclaration.getType();
String returnTypeName = methodReturnType.toString();
String newBody = null;

for(int i = 0; i < 20; i++) {
String fieldName = getFieldName(returnTypeName, i);
if(classDeclaration.getFieldByName(fieldName).isEmpty()) {
ObjectCreationExpr expression = new ObjectCreationExpr();
expression.setType(returnTypeName);
expression.addArgument(StaticJavaParser.parseExpression("(byte)1"));
FieldDeclaration fieldDeclaration = classDeclaration.addFieldWithInitializer(methodReturnType, fieldName, expression, Modifier.Keyword.PRIVATE, Modifier.Keyword.FINAL);

Position begin = new Position(0, 0);
Position end = new Position(0, 0);
Range range = new Range(begin, end);
fieldDeclaration.setRange(range);
String methodCaller = caller.toString();
newBody = GET_OBJECT_TEMPLATE
.replace(TEMPLATE_TAG_METHOD, methodCaller)
.replace(TEMPLATE_TEMP_FIELD, fieldName);
break;
}
}

BlockStmt body = null;
try {
BodyDeclaration<?> bodyDeclaration = StaticJavaParser.parseBodyDeclaration(newBody);
InitializerDeclaration initializerDeclaration = (InitializerDeclaration)bodyDeclaration;
body = initializerDeclaration.getBody();
}
catch(Throwable t) {
String className = classDeclaration.getNameAsString();
System.err.println("Error Class: " + className + "\n" + newBody);
throw t;
}
return body;
}

private static String getFieldName(String type, int number) {
return TEMPLATE_TEMP_FIELD.replace(TEMPLATE_TAG_TYPE, type).replace(TEMPLATE_TAG_NUM, String.valueOf(number));
}

private static MethodDeclaration generateNativeMethod(MethodDeclaration methodDeclaration) {
String methodName = methodDeclaration.getNameAsString();
NodeList<Parameter> methodParameters = methodDeclaration.getParameters();
Type methodReturnType = methodDeclaration.getType();
boolean isStatic = methodDeclaration.isStatic();

// Clone some generated idl method settings
MethodDeclaration nativeMethod = new MethodDeclaration();
nativeMethod.setName(methodName + "NATIVE");
nativeMethod.setModifiers(Modifier.createModifierList(Modifier.Keyword.PRIVATE, Modifier.Keyword.STATIC, Modifier.Keyword.NATIVE));
nativeMethod.removeBody();

if(!isStatic) {
// Only generate addr if it's not a static method
nativeMethod.addAndGetParameter("long", "addr");
}

for(int i = 0; i < methodParameters.size(); i++) {
Parameter parameter = methodParameters.get(i);
String nameAsString = parameter.getNameAsString();
Type type = parameter.getType();
if(type.isPrimitiveType()) {
nativeMethod.addParameter(type.clone(), nameAsString);
}
else {
String pointerMethod = nameAsString + "Addr";
nativeMethod.addParameter("long", pointerMethod);
}
}
// If the return type is an object we need to return a pointer.
if(methodReturnType.isClassOrInterfaceType()) {
// Class Object needs to return a pointer
Type type = StaticJavaParser.parseType(long.class.getSimpleName());
nativeMethod.setType(type);
}
else {
nativeMethod.setType(methodReturnType);
}
return nativeMethod;
}

private static ReturnStmt getReturnStmt(MethodDeclaration idlMethodDeclaration) {
BlockStmt blockStmt = idlMethodDeclaration.getBody().get();
NodeList<Statement> statements = blockStmt.getStatements();
if(statements.size() > 0) {
// Find the return block and add the caller
Statement statement = blockStmt.getStatement(0);
return (ReturnStmt)statement;
}
else {
// should not go here
throw new RuntimeException("Should not go here");
}
}

private static MethodDeclaration containsMethod(ClassOrInterfaceDeclaration classOrInterfaceDeclaration, IDLMethod idlMethod) {
Expand Down
Loading

0 comments on commit dd6dd07

Please sign in to comment.