package scriptingLanguage.variables;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import scriptingLanguage.Interpreter;
import scriptingLanguage.Token;
import scriptingLanguage.Type;
import scriptingLanguage.errors.InterpreterException;
import scriptingLanguage.errors.VariableNotFoundException;
import scriptingLanguage.frames.AbstractFrame;
public class JavaClass<T> extends AbstractClass<Class<? extends T>> {
public JavaClass(String name, Class<? extends T> source) {
this(name, source, new Type<JavaClass<?>>(name));
}
public JavaClass(String name, Class<? extends T> source, Type<?> tokenType) {
super(name, source, tokenType);
}
public Method getMethod(String name, AbstractClass<?>... parameters) throws VariableNotFoundException {
for (Method method : getSource().getMethods()) {
if (!method.getName().equals(name))
continue;
//TODO figure out how to get the closest match
Class<?>[] parameterTypes = method.getParameterTypes();
boolean matches = true;
for (int i = 0; i < parameterTypes.length; i++) {
if (!parameterTypes[i].isAssignableFrom(parameters[i].getClass())) {
matches = false;
break;
}
}
if (matches)
return method;
}
name = name + ":{";
if (parameters.length > 0) {
for (AbstractClass<?> clazz : parameters)
name = name + clazz.getName() + ", ";
name = name.substring(0, name.length() - 2);
}
throw new VariableNotFoundException("No methods that match " + name + "} exist in objects with the type, " + getSource().getName());
}
public Token eval(Object source) {
return new Token(new JavaObject<>(this, (T) source), getTokenType());
}
@Override
public Token eval(AbstractClass<?> caller, Token parameters, AbstractFrame frame) throws ArrayIndexOutOfBoundsException, IllegalArgumentException, InterpreterException {
ArrayList<Token> params = Interpreter.evalFunctionArguments(caller, parameters, frame);
AbstractClass<?>[] p = new AbstractClass<?>[params.size()];
for (int i = 0; i < params.size(); i++)
p[i] = ((Variable<?>) params.get(i).getCar()).getType();
for (Constructor<?> constructor : getSource().getConstructors()) {
//TODO figure out how to get the closest match
Class<?>[] parameterTypes = constructor.getParameterTypes();
boolean matches = true;
for (int i = 0; i < parameterTypes.length; i++)
if (!parameterTypes[i].isAssignableFrom((Class<?>) p[i].getSource())) {
matches = false;
break;
}
if (matches) {
Object[] p2 = new Object[p.length];
for (int i = 0; i < params.size(); i++)
p2[i] = ((Variable<?>) params.get(i).getCar()).getSource();
try {
return new Token(new JavaObject<T>(this, (T) constructor.newInstance(p2)), getTokenType());
}
catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
String name = getName() + ":{";
if (p.length > 0) {
for (AbstractClass<?> clazz : p)
name = name + clazz.getName() + ", ";
name = name.substring(0, name.length() - 2);
}
throw new VariableNotFoundException("No methods that match " + name + "} exist in objects with the type, " + getSource().getName());
}
@Override
public boolean equals(Object o) {
if (o instanceof JavaClass)
return getSource().equals(((JavaClass<?>) o).getSource());
return false;
}
@Override
public int extend(AbstractClass<?> type) {
if (!(type instanceof JavaClass) || !((JavaClass<?>) type).getSource().isAssignableFrom(getSource()))
return -1;
//Maybe some recursion through superclasses and interfaces? Cross-check with the isAssignableFrom trick?
return getSource().isAssignableFrom(((JavaClass<?>) type).getSource()) ? 1 : 0; //TODO figure out how do get distance
}
@Override
public String getName() {
return getSource().getName();
}
@Override
public Variable<Class<? extends T>> clone() {
return new JavaClass<T>(getName(), getSource(), getTokenType());
}
@Override
public Token makePlaceholder() {
return new Token(new JavaObject<T>(this, null), getTokenType());
}
}