package php.runtime.lang;
import php.runtime.Memory;
import php.runtime.common.HintType;
import php.runtime.common.collections.map.HashedMap;
import php.runtime.env.Environment;
import php.runtime.exceptions.support.ErrorType;
import php.runtime.invoke.ObjectInvokeHelper;
import php.runtime.lang.support.IStaticVariables;
import php.runtime.memory.ArrayMemory;
import php.runtime.memory.ObjectMemory;
import php.runtime.memory.ReferenceMemory;
import php.runtime.reflection.ClassEntity;
import php.runtime.reflection.ParameterEntity;
import java.util.Arrays;
import java.util.Map;
import static php.runtime.annotation.Reflection.*;
@Name("Closure")
public abstract class Closure extends BaseObject implements IStaticVariables, Cloneable {
protected Memory[] uses;
private Map<String, ReferenceMemory> statics;
protected Memory self = Memory.NULL;
protected String scope = null;
/*public Closure(Environment env, ClassEntity closure, Memory self, Memory[] uses) {
this(env, closure, self, null, uses);
}*/
public Closure(Environment env, ClassEntity closure, Memory self, String scope, Memory[] uses) {
super(closure);
this.self = self;
this.scope = scope;
if (env != null && (this.scope == null || this.scope.isEmpty())) {
this.scope = env.getLateStatic();
}
if (this.scope != null && this.scope.isEmpty()) {
this.scope = null;
}
this.uses = uses;
}
@Signature
abstract public Memory __invoke(Environment env, Memory... args);
public Memory[] getUses() {
return uses == null ? new Memory[0] : uses;
}
@Signature({@Arg("prop"), @Arg("value")})
public Memory __set(Environment env, Memory... args){
env.error(ErrorType.E_ERROR, "Closure object cannot have properties");
return Memory.NULL;
}
@Signature({@Arg("prop")})
public Memory __get(Environment env, Memory... args){
return __set(env, args);
}
@Signature({@Arg("prop")})
public Memory __unset(Environment env, Memory... args){
return __set(env, args);
}
@Signature({@Arg("prop")})
public Memory __isset(Environment env, Memory... args){
return __set(env, args);
}
@Override
public Memory getStatic(String name){
if (statics == null)
return null;
return statics.get(name);
}
public String getScope() {
return scope;
}
public Memory getSelf() {
return self;
}
public Memory getOrCreateStatic(String name, Memory initValue){
if (statics == null)
statics = new HashedMap<String, ReferenceMemory>();
ReferenceMemory result = statics.get(name);
if (result == null) {
result = new ReferenceMemory(initValue);
statics.put(name, result);
}
return result;
}
@Signature({
@Arg("newThis"),
@Arg(value = "parameters", type = HintType.VARARG, optional = @Optional("null"))
})
public Memory call(Environment env, Memory... args) throws Throwable {
ParameterEntity.validateTypeHinting(env, 1, args, HintType.OBJECT, true);
Closure newClosure = (Closure) this.clone();
newClosure.self = args[0];
newClosure.scope = newClosure.self.toValue(ObjectMemory.class).getReflection().getName();
return ObjectInvokeHelper.invokeMethod(
newClosure, newClosure.getReflection().methodMagicInvoke, env, env.trace(),
Arrays.copyOfRange(args, 1, args.length)
);
}
@Signature({@Arg("newThis"), @Arg(value = "newScope", optional = @Optional("static"))})
public Memory bindTo(Environment env, Memory... args) throws CloneNotSupportedException {
ParameterEntity.validateTypeHinting(env, 1, args, HintType.OBJECT, true);
Closure newClosure = (Closure) this.clone();
newClosure.self = args[0];
newClosure.scope = args[1].toString();
return new ObjectMemory(newClosure);
}
@Signature({
@Arg(value = "closure", typeClass = "Closure"),
@Arg(value = "newThis"),
@Arg(value = "newScope", optional = @Optional("static"))
})
public static Memory bind(Environment env, Memory... args) throws CloneNotSupportedException {
ParameterEntity.validateTypeHinting(env, 2, args, HintType.OBJECT, true);
Closure closure = args[0].toObject(Closure.class);
Closure newClosure = (Closure)closure.clone();
newClosure.self = args[0];
newClosure.scope = args[1].toString();
return new ObjectMemory(newClosure);
}
}