/*******************************************************************************
* Copyright (c) 2013 CWI
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*
* * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI
* * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI
* * Paul Klint - Paul.Klint@cwi.nl - CWI
* * Anya Helene Bagge - anya@ii.uib.no - UiB
*
* Based on code by:
*
* * Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation
*******************************************************************************/
package org.rascalmpl.value.impl.reference;
import java.util.Map.Entry;
import org.rascalmpl.value.IMap;
import org.rascalmpl.value.IMapWriter;
import org.rascalmpl.value.ITuple;
import org.rascalmpl.value.IValue;
import org.rascalmpl.value.exceptions.FactTypeUseException;
import org.rascalmpl.value.exceptions.UnexpectedMapKeyTypeException;
import org.rascalmpl.value.exceptions.UnexpectedMapValueTypeException;
import org.rascalmpl.value.impl.AbstractWriter;
import org.rascalmpl.value.type.Type;
import org.rascalmpl.value.type.TypeFactory;
/*package*/ class MapWriter extends AbstractWriter implements IMapWriter {
private Type staticMapType;
private Type staticKeyType;
private Type staticValueType;
private final boolean inferred;
private final java.util.HashMap<IValue, IValue> mapContent;
private Map constructedMap;
/*package*/ MapWriter(){
super();
this.staticMapType = TypeFactory.getInstance().mapType(
TypeFactory.getInstance().voidType(),
TypeFactory.getInstance().voidType());
this.staticKeyType = TypeFactory.getInstance().voidType();
this.staticValueType = TypeFactory.getInstance().voidType();
this.inferred = true;
mapContent = new java.util.HashMap<>();
}
/*package*/ MapWriter(Type mapType){
super();
if(mapType.isFixedWidth() && mapType.getArity() >= 2) {
mapType = TypeFactory.getInstance().mapTypeFromTuple(mapType);
}
this.staticMapType = mapType;
this.staticKeyType = mapType.getKeyType();
this.staticValueType = mapType.getValueType();
this.inferred = false;
mapContent = new java.util.HashMap<>();
}
private static void check(Type key, Type value, Type keyType, Type valueType)
throws FactTypeUseException {
if (!key.isSubtypeOf(keyType)) {
throw new UnexpectedMapKeyTypeException(keyType, key);
}
if (!value.isSubtypeOf(valueType)) {
throw new UnexpectedMapValueTypeException(valueType, value);
}
}
private void checkMutation() {
if (constructedMap != null)
throw new UnsupportedOperationException(
"Mutation of a finalized list is not supported.");
}
@Override
public void putAll(IMap map) throws FactTypeUseException{
checkMutation();
for(IValue key : map){
IValue value = map.get(key);
updateTypes(key, value);
mapContent.put(key, value);
}
}
private void updateTypes(IValue key, IValue value) {
if (inferred) {
staticKeyType = staticKeyType.lub(key.getType());
staticValueType = staticValueType.lub(value.getType());
}
}
@Override
public void putAll(java.util.Map<IValue, IValue> map) throws FactTypeUseException{
checkMutation();
for(Entry<IValue, IValue> entry : map.entrySet()){
IValue value = entry.getValue();
updateTypes(entry.getKey(), value);
check(entry.getKey().getType(), value.getType(), staticKeyType, staticValueType);
mapContent.put(entry.getKey(), value);
}
}
@Override
public void put(IValue key, IValue value) throws FactTypeUseException{
checkMutation();
updateTypes(key,value);
mapContent.put(key, value);
}
@Override
public void insert(IValue... value) throws FactTypeUseException {
for(IValue tuple : value){
ITuple t = (ITuple) tuple;
IValue key = t.get(0);
IValue value2 = t.get(1);
updateTypes(key,value2);
put(key, value2);
}
}
@Override
public IMap done(){
// Temporary fix of the static vs dynamic type issue
Type dynamicKeyType = TypeFactory.getInstance().voidType();
Type dynamicValueType = TypeFactory.getInstance().voidType();
for (java.util.Map.Entry<IValue, IValue> entry : mapContent.entrySet()) {
dynamicKeyType = dynamicKeyType.lub(entry.getKey().getType());
dynamicValueType = dynamicValueType.lub(entry.getValue().getType());
}
// ---
if (constructedMap == null) {
Type dynamicMapType = TypeFactory.getInstance().mapType(
dynamicKeyType, staticMapType.getKeyLabel(),
dynamicValueType, staticMapType.getValueLabel());
constructedMap = new Map(dynamicMapType, mapContent);
}
return constructedMap;
}
}