/**
*
*/
package it.xsemantics.runtime;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.eclipse.xtext.xbase.lib.Functions;
import org.eclipse.xtext.xbase.lib.IterableExtensions;
/**
* Implements the environment for a typing judgment
*
* @author Lorenzo Bettini
*
*/
public class RuleEnvironment {
protected Map<Object, Object> environment = new LinkedHashMap<Object, Object>();
protected RuleEnvironment next = null;
public RuleEnvironment(RuleEnvironment e) {
if (e == null) {
environment = new LinkedHashMap<Object, Object>();
} else {
environment = new LinkedHashMap<Object, Object>(e.getEnvironment());
}
}
public RuleEnvironment() {
}
public RuleEnvironment(RuleEnvironmentEntry environmentEntry) {
add(environmentEntry);
}
public RuleEnvironment(RuleEnvironment firstComponent,
RuleEnvironment secondComponent) {
this(firstComponent);
environment.putAll(secondComponent.getEnvironment());
}
public Map<Object, Object> getEnvironment() {
return environment;
}
public RuleEnvironment getNext() {
return next;
}
public void setNext(RuleEnvironment next) {
this.next = next;
}
public void setNext(RuleEnvironmentEntry runtimeEnvironmentEntry) {
RuleEnvironment next2 = new RuleEnvironment();
setNext(next2);
next2.add(runtimeEnvironmentEntry);
}
public void add(RuleEnvironmentEntry runtimeEnvironmentEntry) {
add(runtimeEnvironmentEntry.getLeft(),
runtimeEnvironmentEntry.getRight());
}
public boolean add(Object o1, Object o2) {
return add(o1, o2, false);
}
/**
* If checkExist is true, before inserting, also checks that there is no
* other statement in the environment with left equal to the passed
* typingStatement left (otherwise returns false=
*
* @param typingStatement
* @param checkExist
* @return
*/
public boolean add(Object o1, Object o2, boolean checkExist) {
if (checkExist && environment.containsKey(o1)) {
return false;
}
environment.put(o1, o2);
return true;
}
/**
* If the key is not found in this environment tries recursively with the
* next one
*
* @param key
* @return
*/
public Object get(Object key) {
Object object = environment.get(key);
if (object == null && next != null) {
return next.get(key);
}
return object;
}
/**
* Adds all the entries of the passed environment to this one (existing
* mappings for the same key will be overwritten).
* @param ruleEnvironment
*/
public void increment(RuleEnvironment ruleEnvironment) {
if (ruleEnvironment != null) {
environment.putAll(ruleEnvironment.getEnvironment());
}
}
/**
* Same as add
* @param runtimeEnvironmentEntry
*/
public void increment(RuleEnvironmentEntry runtimeEnvironmentEntry) {
increment(runtimeEnvironmentEntry.getLeft(),
runtimeEnvironmentEntry.getRight());
}
/**
* Same as add
* @param o1
* @param o2
*/
public void increment(Object o1, Object o2) {
add(o1, o2);
}
/**
* Removes all the mapping that have as keys the keys of the
* passed environment.
* @param ruleEnvironment
*/
public void decrement(RuleEnvironment ruleEnvironment) {
if (ruleEnvironment != null) {
environment.keySet().removeAll(
ruleEnvironment.getEnvironment().keySet());
}
}
/**
* Remove the mapping with the passed object as key
* @param o1
*/
public void decrement(Object o1) {
environment.remove(o1);
}
/**
* Adds all the entries of the passed environment, but it returns false
* if there are mappings in the passed environment with the same key
* of the current environment; the current environment is NOT restored
* to its original state in case of failure.
* @param ruleEnvironment if null it's succeeds
* @return
*/
public boolean union(RuleEnvironment ruleEnvironment) {
if (ruleEnvironment == null) {
return true;
}
Set<Entry<Object, Object>> entrySet = ruleEnvironment
.getEnvironment().entrySet();
for (Entry<Object, Object> entry : entrySet) {
if (!union(entry.getKey(), entry.getValue())) {
return false;
}
}
return true;
}
public boolean union(RuleEnvironmentEntry runtimeEnvironmentEntry) {
return union(runtimeEnvironmentEntry.getLeft(),
runtimeEnvironmentEntry.getRight());
}
public boolean union(Object o1, Object o2) {
return add(o1, o2, true);
}
@Override
public String toString() {
if (isEmpty()) {
return "";
}
StringBuilder buffer = new StringBuilder(
IterableExtensions.join(
IterableExtensions.map(getEnvironment().entrySet(),
new Functions.Function1<Entry<Object, Object>, String>() {
@Override
public String apply(Map.Entry<Object,Object> p) {
return p.getKey() + " -> " + p.getValue();
}
}
),
", "
)
);
if (next != null) {
buffer.append(" :: [");
buffer.append(next.toString());
buffer.append("]");
}
return buffer.toString();
}
/**
* @since 1.5
*/
public boolean isEmpty() {
return environment.isEmpty();
}
/**
* @since 1.5
*/
public int size() {
return environment.size();
}
/**
* @since 1.5
*/
public void clear() {
environment.clear();
}
/**
* @since 1.5
*/
public Set<Object> keySet() {
return environment.keySet();
}
/**
* @since 1.5
*/
public Collection<Object> values() {
return environment.values();
}
/**
* @since 1.5
*/
public Set<Entry<Object, Object>> entrySet() {
return environment.entrySet();
}
/**
* If the passed object is a RuleEnvironment then returns equals on the
* two {@link Map} contained objects.
*
* @since 1.5
*/
@Override
public boolean equals(Object o) {
if (o instanceof RuleEnvironment) {
return environment.equals(((RuleEnvironment) o).getEnvironment());
}
return super.equals(o);
}
/**
* @since 1.5
*/
@Override
public int hashCode() {
return environment.hashCode();
}
}