package php.runtime.reflection;
import php.runtime.Memory;
import php.runtime.common.Messages;
import php.runtime.env.Environment;
import php.runtime.env.TraceInfo;
import php.runtime.exceptions.support.ErrorType;
import php.runtime.ext.support.Extension;
import php.runtime.ext.support.compile.CompileFunction;
import php.runtime.ext.support.compile.CompileFunctionSpec;
import php.runtime.memory.support.MemoryUtils;
import java.lang.reflect.InvocationTargetException;
public class CompileFunctionEntity extends FunctionEntity {
private final CompileFunctionSpec compileFunctionSpec;
private CompileFunction compileFunction;
public CompileFunctionEntity(Extension extension, CompileFunctionSpec compileFunction) {
super(null);
this.compileFunctionSpec = compileFunction;
this.setName(compileFunction.getName());
this.setExtension(extension);
}
@Override
public boolean isInternal() {
return true;
}
public CompileFunction getCompileFunction() {
if (compileFunction != null) {
return compileFunction;
}
synchronized (compileFunctionSpec) {
if (compileFunction != null) {
return compileFunction;
}
compileFunction = compileFunctionSpec.toFunction();
}
return compileFunction;
}
@Override
public Memory invoke(Environment env, TraceInfo trace, Memory[] arguments) throws Throwable {
CompileFunction.Method method = getCompileFunction().find(arguments.length);
if (method == null){
env.warning(trace, Messages.ERR_EXPECT_LEAST_PARAMS.fetch(
name, compileFunction.getMinArgs(), arguments.length
));
return Memory.NULL;
} else {
if (arguments.length > method.argsCount && !method.isVarArg()) {
env.warning(trace, Messages.ERR_EXPECT_EXACTLY_PARAMS,
name, method.argsCount, arguments.length
);
return Memory.NULL;
}
}
Class<?>[] types = method.parameterTypes;
Object[] passed = new Object[ types.length ];
int i = 0;
int j = 0;
for(Class<?> clazz : types) {
boolean isRef = method.references[i];
boolean mutableValue = method.mutableValues[i];
MemoryUtils.Converter<?> converter = method.converters[i];
if (clazz == Memory.class) {
Memory argument = arguments[j];
passed[i] = isRef ? argument : (mutableValue ? argument.toImmutable() : argument.toValue());
j++;
} else if (converter != null) {
passed[i] = converter.run(arguments[j]);
j++;
} else if (clazz == Environment.class) {
passed[i] = env;
} else if (clazz == TraceInfo.class) {
passed[i] = trace;
} else if (i == types.length - 1 && types[i] == Memory[].class){
Memory[] arg = new Memory[arguments.length - i + 1];
if (!isRef){
for(int k = 0; k < arg.length; k++)
arg[i] = arguments[i].toImmutable();
} else {
System.arraycopy(arguments, j, arg, 0, arg.length);
}
passed[i] = arg;
break;
} else {
env.error(trace, ErrorType.E_CORE_ERROR, name + "(): Cannot call this function dynamically");
passed[i] = Memory.NULL;
}
i++;
}
try {
if (method.resultType == void.class){
method.method.invoke(null, passed);
return Memory.NULL;
} else
return MemoryUtils.valueOf(method.method.invoke(null, passed));
} catch (InvocationTargetException e){
return env.__throwException(e);
}
}
}