com.badlogic.gdx.jnigen.parsing.RobustJavaMethodParser Maven / Gradle / Ivy
/*******************************************************************************
* Copyright 2011 See AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.badlogic.gdx.jnigen.parsing;
import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.BodyDeclaration;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.EnumDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.body.ModifierSet;
import com.github.javaparser.ast.body.Parameter;
import com.github.javaparser.ast.body.TypeDeclaration;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Stack;
public class RobustJavaMethodParser implements JavaMethodParser {
private static final String JNI_MANUAL = "MANUAL";
private static final Map plainOldDataTypes;
private static final Map arrayTypes;
private static final Map bufferTypes;
public static String CustomIgnoreTag = "";
static {
plainOldDataTypes = new HashMap();
plainOldDataTypes.put("boolean", ArgumentType.Boolean);
plainOldDataTypes.put("byte", ArgumentType.Byte);
plainOldDataTypes.put("char", ArgumentType.Char);
plainOldDataTypes.put("short", ArgumentType.Short);
plainOldDataTypes.put("int", ArgumentType.Integer);
plainOldDataTypes.put("long", ArgumentType.Long);
plainOldDataTypes.put("float", ArgumentType.Float);
plainOldDataTypes.put("double", ArgumentType.Double);
arrayTypes = new HashMap();
arrayTypes.put("boolean", ArgumentType.BooleanArray);
arrayTypes.put("byte", ArgumentType.ByteArray);
arrayTypes.put("char", ArgumentType.CharArray);
arrayTypes.put("short", ArgumentType.ShortArray);
arrayTypes.put("int", ArgumentType.IntegerArray);
arrayTypes.put("long", ArgumentType.LongArray);
arrayTypes.put("float", ArgumentType.FloatArray);
arrayTypes.put("double", ArgumentType.DoubleArray);
bufferTypes = new HashMap();
bufferTypes.put("Buffer", ArgumentType.Buffer);
bufferTypes.put("ByteBuffer", ArgumentType.ByteBuffer);
bufferTypes.put("CharBuffer", ArgumentType.CharBuffer);
bufferTypes.put("ShortBuffer", ArgumentType.ShortBuffer);
bufferTypes.put("IntBuffer", ArgumentType.IntBuffer);
bufferTypes.put("LongBuffer", ArgumentType.LongBuffer);
bufferTypes.put("FloatBuffer", ArgumentType.FloatBuffer);
bufferTypes.put("DoubleBuffer", ArgumentType.DoubleBuffer);
}
Stack classStack = new Stack();
@Override
public ArrayList parse (String classFile) throws Exception {
CompilationUnit unit = JavaParser.parse(new ByteArrayInputStream(classFile.getBytes()));
ArrayList methods = new ArrayList();
getJavaMethods(methods, getOuterClass(unit));
ArrayList methodBodies = getNativeCodeBodies(classFile);
ArrayList sections = getJniSections(classFile);
alignMethodBodies(methods, methodBodies);
ArrayList segments = sortMethodsAndSections(methods, sections);
return segments;
}
private ArrayList sortMethodsAndSections (ArrayList methods, ArrayList sections) {
ArrayList segments = new ArrayList();
segments.addAll(methods);
segments.addAll(sections);
Collections.sort(segments, new Comparator() {
@Override
public int compare (JavaSegment o1, JavaSegment o2) {
return o1.getStartIndex() - o2.getStartIndex();
}
});
return segments;
}
private void alignMethodBodies (ArrayList methods, ArrayList methodBodies) {
for (JavaMethod method : methods) {
for (JniSection section : methodBodies) {
if (method.getEndIndex() == section.getStartIndex()) {
if (section.getNativeCode().startsWith(JNI_MANUAL)) {
section.setNativeCode(section.getNativeCode().substring(JNI_MANUAL.length()));
method.setManual(true);
}
method.setNativeCode(section.getNativeCode());
break;
}
}
}
}
private void getJavaMethods (ArrayList methods, TypeDeclaration type) {
classStack.push(type);
if (type.getMembers() != null) {
for (BodyDeclaration member : type.getMembers()) {
if (member instanceof ClassOrInterfaceDeclaration || member instanceof EnumDeclaration) {
getJavaMethods(methods, (TypeDeclaration)member);
} else {
if (member instanceof MethodDeclaration) {
MethodDeclaration method = (MethodDeclaration)member;
if (!ModifierSet.hasModifier(((MethodDeclaration)member).getModifiers(), ModifierSet.NATIVE)) continue;
methods.add(createMethod(method));
}
}
}
}
classStack.pop();
}
private JavaMethod createMethod (MethodDeclaration method) {
String className = classStack.peek().getName();
String name = method.getName();
boolean isStatic = ModifierSet.hasModifier(method.getModifiers(), ModifierSet.STATIC);
String returnType = method.getType().toString();
ArrayList arguments = new ArrayList();
if (method.getParameters() != null) {
for (Parameter parameter : method.getParameters()) {
arguments.add(new Argument(getArgumentType(parameter), parameter.getId().getName()));
}
}
return new JavaMethod(className, name, isStatic, returnType, null, arguments, method.getBeginLine(), method.getEndLine());
}
private ArgumentType getArgumentType (Parameter parameter) {
String[] typeTokens = parameter.getType().toString().split("\\.");
String type = typeTokens[typeTokens.length - 1];
int arrayDim = 0;
for (int i = 0; i < type.length(); i++) {
if (type.charAt(i) == '[') arrayDim++;
}
type = type.replace("[", "").replace("]", "");
if (arrayDim >= 1) {
if (arrayDim > 1) return ArgumentType.ObjectArray;
ArgumentType arrayType = arrayTypes.get(type);
if (arrayType == null) {
return ArgumentType.ObjectArray;
}
return arrayType;
}
if (plainOldDataTypes.containsKey(type)) return plainOldDataTypes.get(type);
if (bufferTypes.containsKey(type)) return bufferTypes.get(type);
if (type.equals("String")) return ArgumentType.String;
return ArgumentType.Object;
}
private TypeDeclaration getOuterClass (CompilationUnit unit) {
for (TypeDeclaration type : unit.getTypes()) {
if (type instanceof ClassOrInterfaceDeclaration || type instanceof EnumDeclaration) return type;
}
throw new RuntimeException("Couldn't find class, is your java file empty?");
}
private ArrayList getJniSections (String classFile) {
ArrayList sections = getComments(classFile);
Iterator iter = sections.iterator();
while (iter.hasNext()) {
JniSection section = iter.next();
if (!section.getNativeCode().startsWith("JNI")) {
iter.remove();
} else {
section.setNativeCode(section.getNativeCode().substring(3));
}
}
return sections;
}
private ArrayList getNativeCodeBodies (String classFile) {
ArrayList sections = getComments(classFile);
Iterator iter = sections.iterator();
while (iter.hasNext()) {
JniSection section = iter.next();
if (section.getNativeCode().startsWith("JNI")) iter.remove();
if (section.getNativeCode().startsWith("-{")) iter.remove();
if (!CustomIgnoreTag.isEmpty() && section.getNativeCode().startsWith(CustomIgnoreTag)) iter.remove();
}
return sections;
}
private ArrayList getComments (String classFile) {
ArrayList sections = new ArrayList();
boolean inComment = false;
int start = 0;
int startLine = 0;
int line = 1;
for (int i = 0; i < classFile.length() - 2; i++) {
char c1 = classFile.charAt(i);
char c2 = classFile.charAt(i + 1);
char c3 = classFile.charAt(i + 2);
if (c1 == '\n') line++;
if (!inComment) {
if (c1 == '/' && c2 == '*' && c3 != '*') {
inComment = true;
start = i;
startLine = line;
}
} else {
if (c1 == '*' && c2 == '/') {
sections.add(new JniSection(classFile.substring(start + 2, i), startLine, line));
inComment = false;
}
}
}
return sections;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy