/******************************************************************************* * * Copyright (C) 2008 Fujitsu Services Ltd. * * Author: Nick Battle * * This file is part of VDMJ. * * VDMJ is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * VDMJ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with VDMJ. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ package org.overture.interpreter.values; import java.util.Set; import org.overture.ast.analysis.AnalysisException; import org.overture.ast.types.AInMapMapType; import org.overture.ast.types.PType; import org.overture.ast.types.SMapType; import org.overture.interpreter.runtime.Context; import org.overture.interpreter.runtime.ValueException; public class MapValue extends Value { private static final long serialVersionUID = 1L; public final ValueMap values; public MapValue() { this.values = new ValueMap(); } public MapValue(ValueMap values) { this.values = values; } @Override public ValueMap mapValue(Context ctxt) { return values; } @Override public Value getUpdatable(ValueListenerList listeners) { ValueMap nm = new ValueMap(); for (Value k : values.keySet()) { Value v = values.get(k).getUpdatable(listeners); nm.put(k, v); } return UpdatableValue.factory(new MapValue(nm), listeners); } @Override public Value getConstant() { ValueMap nm = new ValueMap(); for (Value k : values.keySet()) { Value v = values.get(k).getConstant(); nm.put(k, v); } return new MapValue(nm); } public Value lookup(Value arg, Context ctxt) throws ValueException { Value v = values.get(arg); if (v == null) { abort(4061, "No such key value in map: " + arg, ctxt); } return v; } @Override public boolean equals(Object other) { if (other instanceof Value) { Value val = ((Value) other).deref(); if (val instanceof MapValue) { MapValue ot = (MapValue) val; return values.equals(ot.values); } } return false; } @Override public String toString() { return values.isEmpty() ? "{|->}" : values.toString(); } @Override public int hashCode() { return values.hashCode(); } @Override public String kind() { return "map"; } @Override protected Value convertValueTo(PType to, Context ctxt, Set<PType> done) throws AnalysisException { if (to instanceof SMapType) { if (to instanceof AInMapMapType && !values.isInjective()) { abort(4062, "Cannot convert non-injective map to an inmap", ctxt); } SMapType mapto = ctxt.assistantFactory.createPTypeAssistant().getMap(to); ValueMap nm = new ValueMap(); for (Value k : values.keySet()) { Value v = values.get(k); Value dom = k.convertValueTo(mapto.getFrom(), ctxt); Value rng = v.convertValueTo(mapto.getTo(), ctxt); Value old = nm.put(dom, rng); if (old != null && !old.equals(rng)) { abort(4063, "Duplicate map keys have different values: " + dom, ctxt); } } return new MapValue(nm); } else { return super.convertValueTo(to, ctxt, done); } } @Override public Object clone() { return new MapValue((ValueMap) values.clone()); } }