org.mvel2.ast.Proto Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mvel2 Show documentation
Show all versions of mvel2 Show documentation
MVEL is a powerful expression language for Java-based applications.
It provides a plethora of features and is suited for everything
from the smallest property binding and extraction, to full blown scripts.
package org.mvel2.ast;
import org.mvel2.CompileException;
import org.mvel2.ParserContext;
import org.mvel2.UnresolveablePropertyException;
import org.mvel2.compiler.ExecutableStatement;
import org.mvel2.integration.VariableResolver;
import org.mvel2.integration.VariableResolverFactory;
import org.mvel2.integration.impl.MapVariableResolverFactory;
import org.mvel2.integration.impl.SimpleValueResolver;
import org.mvel2.util.CallableProxy;
import org.mvel2.util.SimpleIndexHashMapWrapper;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import static org.mvel2.DataConversion.canConvert;
import static org.mvel2.DataConversion.convert;
public class Proto extends ASTNode {
private String name;
private Map receivers;
private int cursorStart;
private int cursorEnd;
public Proto(String name, ParserContext pCtx) {
super(pCtx);
this.name = name;
this.receivers = new SimpleIndexHashMapWrapper();
}
public Receiver declareReceiver(String name, Function function) {
Receiver r = new Receiver(null, ReceiverType.FUNCTION, function);
receivers.put(name, r);
return r;
}
public Receiver declareReceiver(String name, Class type, ExecutableStatement initCode) {
Receiver r = new Receiver(null, ReceiverType.PROPERTY, initCode);
receivers.put(name, r);
return r;
}
public Receiver declareReceiver(String name, ReceiverType type, ExecutableStatement initCode) {
Receiver r = new Receiver(null, type, initCode);
receivers.put(name, r);
return r;
}
public ProtoInstance newInstance(Object ctx, Object thisCtx, VariableResolverFactory factory) {
return new ProtoInstance(this, ctx, thisCtx, factory);
}
@Override
public Object getReducedValue(Object ctx, Object thisValue, VariableResolverFactory factory) {
factory.createVariable(name, this);
return this;
}
@Override
public Object getReducedValueAccelerated(Object ctx, Object thisValue, VariableResolverFactory factory) {
factory.createVariable(name, this);
return this;
}
public class Receiver implements CallableProxy {
private ReceiverType type;
private Object receiver;
private ExecutableStatement initValue;
private ProtoInstance instance;
public Receiver(ProtoInstance protoInstance, ReceiverType type, Object receiver) {
this.instance = protoInstance;
this.type = type;
this.receiver = receiver;
}
public Receiver(ProtoInstance protoInstance, ReceiverType type, ExecutableStatement stmt) {
this.instance = protoInstance;
this.type = type;
this.initValue = stmt;
}
public Object call(Object ctx, Object thisCtx, VariableResolverFactory factory, Object[] parms) {
switch (type) {
case FUNCTION:
return ((Function) receiver).call(ctx, thisCtx, new InvokationContextFactory(factory, instance.instanceStates), parms);
case PROPERTY:
return receiver;
case DEFERRED:
throw new CompileException("unresolved prototype receiver", expr, start);
}
return null;
}
public Receiver init(ProtoInstance instance, Object ctx, Object thisCtx, VariableResolverFactory factory) {
return new Receiver(instance, type,
type == ReceiverType.PROPERTY && initValue != null ? initValue.getValue(ctx, thisCtx, factory) :
receiver);
}
public void setType(ReceiverType type) {
this.type = type;
}
public void setInitValue(ExecutableStatement initValue) {
this.initValue = initValue;
}
}
public enum ReceiverType {
DEFERRED, FUNCTION, PROPERTY
}
public class ProtoInstance implements Map {
private Proto protoType;
private VariableResolverFactory instanceStates;
private SimpleIndexHashMapWrapper receivers;
public ProtoInstance(Proto protoType, Object ctx, Object thisCtx, VariableResolverFactory factory) {
this.protoType = protoType;
receivers = new SimpleIndexHashMapWrapper();
for (Map.Entry entry : protoType.receivers.entrySet()) {
receivers.put(entry.getKey(), entry.getValue().init(this, ctx, thisCtx, factory));
}
instanceStates = new ProtoContextFactory(receivers);
}
public Proto getProtoType() {
return protoType;
}
public int size() {
return receivers.size();
}
public boolean isEmpty() {
return receivers.isEmpty();
}
public boolean containsKey(Object key) {
return receivers.containsKey(key);
}
public boolean containsValue(Object value) {
return receivers.containsValue(value);
}
public Receiver get(Object key) {
return receivers.get(key);
}
public Receiver put(String key, Receiver value) {
return receivers.put(key, value);
}
public Receiver remove(Object key) {
return receivers.remove(key);
}
public void putAll(Map m) {
}
public void clear() {
}
public Set keySet() {
return receivers.keySet();
}
public Collection values() {
return receivers.values();
}
public Set> entrySet() {
return receivers.entrySet();
}
}
@Override
public String getName() {
return name;
}
@Override
public String toString() {
return "proto " + name;
}
public class ProtoContextFactory extends MapVariableResolverFactory {
private final SimpleIndexHashMapWrapper variableResolvers;
public ProtoContextFactory(SimpleIndexHashMapWrapper variables) {
super(variables);
variableResolvers = new SimpleIndexHashMapWrapper(variables, true);
}
@Override
public VariableResolver createVariable(String name, Object value) {
VariableResolver vr;
try {
(vr = getVariableResolver(name)).setValue(value);
return vr;
}
catch (UnresolveablePropertyException e) {
addResolver(name, vr = new ProtoResolver(variables, name)).setValue(value);
return vr;
}
}
@Override
public VariableResolver createVariable(String name, Object value, Class> type) {
VariableResolver vr;
try {
vr = getVariableResolver(name);
}
catch (UnresolveablePropertyException e) {
vr = null;
}
if (vr != null && vr.getType() != null) {
throw new CompileException("variable already defined within scope: " + vr.getType() + " " + name, expr, start);
}
else {
addResolver(name, vr = new ProtoResolver(variables, name, type)).setValue(value);
return vr;
}
}
@Override
public void setIndexedVariableNames(String[] indexedVariableNames) {
//
}
@Override
public String[] getIndexedVariableNames() {
//
return null;
}
@Override
public VariableResolver createIndexedVariable(int index, String name, Object value, Class> type) {
VariableResolver vr = this.variableResolvers != null ? this.variableResolvers.getByIndex(index) : null;
if (vr != null && vr.getType() != null) {
throw new CompileException("variable already defined within scope: " + vr.getType() + " " + name, expr, start);
}
else {
return createIndexedVariable(variableIndexOf(name), name, value);
}
}
@Override
public VariableResolver createIndexedVariable(int index, String name, Object value) {
VariableResolver vr = variableResolvers.getByIndex(index);
if (vr == null) {
vr = new SimpleValueResolver(value);
variableResolvers.putAtIndex(index, vr);
}
else {
vr.setValue(value);
}
return indexedVariableResolvers[index];
}
@Override
public VariableResolver getIndexedVariableResolver(int index) {
return variableResolvers.getByIndex(index);
}
@Override
public VariableResolver setIndexedVariableResolver(int index, VariableResolver resolver) {
variableResolvers.putAtIndex(index, resolver);
return resolver;
}
@Override
public int variableIndexOf(String name) {
return variableResolvers.indexOf(name);
}
public VariableResolver getVariableResolver(String name) {
VariableResolver vr = variableResolvers.get(name);
if (vr != null) {
return vr;
}
else if (variables.containsKey(name)) {
variableResolvers.put(name, vr = new ProtoResolver(variables, name));
return vr;
}
else if (nextFactory != null) {
return nextFactory.getVariableResolver(name);
}
throw new UnresolveablePropertyException("unable to resolve variable '" + name + "'");
}
}
public class ProtoResolver implements VariableResolver {
private String name;
private Class> knownType;
private Map variableMap;
public ProtoResolver(Map variableMap, String name) {
this.variableMap = variableMap;
this.name = name;
}
public ProtoResolver(Map variableMap, String name, Class knownType) {
this.name = name;
this.knownType = knownType;
this.variableMap = variableMap;
}
public void setName(String name) {
this.name = name;
}
public void setStaticType(Class knownType) {
this.knownType = knownType;
}
public String getName() {
return name;
}
public Class getType() {
return knownType;
}
public void setValue(Object value) {
if (knownType != null && value != null && value.getClass() != knownType) {
if (!canConvert(knownType, value.getClass())) {
throw new CompileException("cannot assign " + value.getClass().getName() + " to type: "
+ knownType.getName(), expr, start);
}
try {
value = convert(value, knownType);
}
catch (Exception e) {
throw new CompileException("cannot convert value of " + value.getClass().getName()
+ " to: " + knownType.getName(), expr, start);
}
}
((Receiver) variableMap.get(name)).receiver = value;
}
public Object getValue() {
return ((Receiver) variableMap.get(name)).receiver;
}
public int getFlags() {
return 0;
}
}
public void setCursorPosition(int start, int end) {
this.cursorStart = start;
this.cursorEnd = end;
}
public int getCursorStart() {
return cursorStart;
}
public int getCursorEnd() {
return cursorEnd;
}
}