/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.ochafik.lang.jnaerator;
import com.ochafik.lang.jnaerator.parser.*;
import static com.ochafik.lang.jnaerator.parser.ElementsHelper.*;
import static com.ochafik.lang.jnaerator.TypeConversion.*;
import com.ochafik.lang.jnaerator.parser.Function.SignatureType;
import com.nativelibs4java.jalico.Pair;
import com.ochafik.util.string.StringUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.bridj.ann.Ptr;
/**
*
* @author ochafik
*/
public class Reifier {
final Result result;
public Reifier(Result result) {
this.result = result;
}
void toDirectFakePointer(Result result, Declaration decl) {
decl.setValueType(typeRef(long.class));
decl.addAnnotation(new Annotation(typeRef(Ptr.class)));
}
boolean isFakePointerRef(Result result, TypeRef tr) {
if (tr instanceof TypeRef.SimpleTypeRef) {
Identifier id = ((TypeRef.SimpleTypeRef) tr).getName();
if (result.isFakePointer(id)) //if (id.equals(ident(result.config.runtime.pointerClass)))
{
return true;
}
}
return false;
}
private void privatize(Declaration d) {
List<Modifier> modifiers = new ArrayList<Modifier>(d.getModifiers());
modifiers.remove(ModifierType.Public);
modifiers.remove(ModifierType.Protected);
modifiers.add(0, ModifierType.Private);
d.setModifiers(modifiers);
}
static String trimAny(String s, String[] prefixes, String[] suffixes) {
String l = s.toLowerCase();
if (prefixes != null) {
for (String prefix : prefixes) {
if (l.startsWith(prefix.toLowerCase())) {
s = s.substring(prefix.length());
break;
}
}
}
if (suffixes != null) {
for (String suffix : suffixes) {
if (l.endsWith(suffix.toLowerCase())) {
s = s.substring(0, s.length() - suffix.length());
break;
}
}
}
return s;
}
public String reifyFunctionName(Result result, String fakePointerName, String functionName) {
String simplifiedPointerName = StringUtils.trimUnderscores(trimAny(fakePointerName, result.config.libraryNamingPrefixes, null));
List<String> prefs = new ArrayList<String>();
if (result.config.libraryNamingPrefixes != null) {
prefs.addAll(Arrays.asList(result.config.libraryNamingPrefixes));
}
prefs.add(fakePointerName);
prefs.add(simplifiedPointerName);
String s = StringUtils.uncapitalize(StringUtils.trimUnderscores(trimAny(functionName, prefs.toArray(new String[prefs.size()]), new String[]{
simplifiedPointerName,
simplifiedPointerName.replaceAll("_", "")
})));
if (s.length() == 0 || result.typeConverter.isJavaKeyword(s)) {
return functionName;
}
return s;
}
public void reifyFakePointer(Struct ptClass, Identifier fullLibraryClassName, String fakePointerName, Signatures signatures) {
Identifier resolvedFakePointer = result.getFakePointer(fullLibraryClassName, ident(fakePointerName));
List<Pair<Identifier, Function>> functionsReifiableInFakePointers = result.getFunctionsReifiableInFakePointer(resolvedFakePointer);
String thisFakePtrRefStr = typeRef(resolvedFakePointer).toString();
if (functionsReifiableInFakePointers == null) {
return;
}
for (Pair<Identifier, Function> p : functionsReifiableInFakePointers) {
Function original = p.getSecond();
Function fDirect = original.clone();
int thisLocation = -1;
List<Integer> fakePointersLocations = new ArrayList<Integer>();
int iArg = 0;
for (Arg arg : fDirect.getArgs()) {
if (isFakePointerRef(result, arg.getValueType())) {
if (iArg == 0 && arg.getValueType().toString().equals(thisFakePtrRefStr)) {
thisLocation = iArg;
}
fakePointersLocations.add(iArg);
toDirectFakePointer(result, arg);
}
iArg++;
}
String indirectRetVarName = "$";
boolean returnsFakePointer = isFakePointerRef(result, fDirect.getValueType());
boolean needsDirect = !fakePointersLocations.isEmpty() || returnsFakePointer;
Expression finalCall = null;
//boolean needsDirect = fDirect.toString().equals(original.toString());
String directFunctionName = null;
if (needsDirect) {
if (returnsFakePointer) {
finalCall = new Expression.New(fDirect.getValueType(), varRef(indirectRetVarName));
toDirectFakePointer(result, fDirect);
}
privatize(fDirect);
if (signatures.addMethod(fDirect)) {
((DeclarationsHolder) original.getParentElement()).addDeclaration(fDirect);
}
if (original.computeSignature(SignatureType.JavaStyle).equals(fDirect.computeSignature(SignatureType.JavaStyle))) {
fDirect.setName(ident(original.getName() + "$direct"));
}
directFunctionName = fDirect.getName().toString();
}
// TODO private
// TODO -reify:ptrname
// TODO -reify:function=name
//
Function f = original.clone();
List<Arg> args = new ArrayList<Arg>(f.getArgs());
f.setModifiers(Collections.EMPTY_LIST);
f.addModifiers(ModifierType.Public);
if (thisLocation < 0) {
f.addModifiers(ModifierType.Static);
}
String functionName = f.getName().toString();
f.setName(ident(reifyFunctionName(result, fakePointerName, functionName)));
Identifier id = p.getFirst();
List<Expression> followedArgs = new ArrayList<Expression>();
//followedArgs.add(thisRef());
iArg = 0;
for (Arg arg : args) {
if (iArg == thisLocation) {
followedArgs.add(methodCall(thisRef(), "getPeer"));
} else if (fakePointersLocations.contains(iArg)) {
followedArgs.add(methodCall(varRef(arg.getName()), "getPeer"));
} else {
followedArgs.add(varRef(arg.getName()));
}
iArg++;
}
if (thisLocation >= 0) {
args.remove(thisLocation);
}
f.setArgs(args);
Expression nlib = expr(typeRef(p.getFirst().clone()));//nativeLibFieldExpr.clone(); // expr(typeRef(id.clone()))
Expression x = methodCall(nlib, needsDirect ? directFunctionName : functionName, followedArgs.toArray(new Expression[followedArgs.size()]));
boolean retVoid = "void".equals(String.valueOf(f.getValueType()));
if (retVoid) {
f.setBody(block(stat(x)));
} else if (needsDirect && finalCall != null) {
VariablesDeclaration vd = new VariablesDeclaration(typeRef(long.class), new Declarator.DirectDeclarator(indirectRetVarName, x));
Expression.ConditionalExpression ce = new Expression.ConditionalExpression();
ce.setTest(expr(varRef(indirectRetVarName), Expression.BinaryOperator.IsEqual, expr(0)));
ce.setThenValue(nullExpr());
ce.setElseValue(finalCall);
f.setBody(block(stat(vd), new Statement.Return(ce)));
} else {
f.setBody(block(new Statement.Return(x)));
}
ptClass.addDeclaration(f);
}
}
}