| 1 | package de.uka.ipd.sdq.simucomframework.variables.stackframe; |
| 2 | |
| 3 | import java.io.Serializable; |
| 4 | import java.util.ArrayList; |
| 5 | import java.util.HashMap; |
| 6 | import java.util.Map.Entry; |
| 7 | |
| 8 | import org.apache.log4j.Logger; |
| 9 | |
| 10 | import de.uka.ipd.sdq.simucomframework.variables.exceptions.ValueNotInFrameException; |
| 11 | |
| 12 | /** |
| 13 | * A stackframe as used in compiler construction to realise variable scopes. |
| 14 | * It is similar to a hashmap hashing variable IDs on variable values. However, |
| 15 | * this map can query its parent maps if the value is not found in it |
| 16 | * @author Steffen Becker |
| 17 | * |
| 18 | * @param <T> |
| 19 | */ |
| 20 | /** |
| 21 | * @author Steffen Becker |
| 22 | * |
| 23 | * @param <T> |
| 24 | */ |
| 25 | public class SimulatedStackframe <T> implements Serializable { |
| 26 | |
| 27 | /** |
| 28 | * |
| 29 | */ |
| 30 | private static final long serialVersionUID = 547392494342021941L; |
| 31 | |
| 32 | private static Logger logger = |
| 33 | Logger.getLogger(SimulatedStackframe.class.getName()); |
| 34 | |
| 35 | private SimulatedStackframe<T> parentFrame = null; |
| 36 | |
| 37 | // Stackframe: Maps ID->Value |
| 38 | private HashMap<String, T> contents = new HashMap<String, T>(); |
| 39 | |
| 40 | public SimulatedStackframe (SimulatedStackframe<T> parent) |
| 41 | { |
| 42 | this.parentFrame = parent; |
| 43 | } |
| 44 | |
| 45 | public SimulatedStackframe () |
| 46 | { |
| 47 | this.parentFrame = null; |
| 48 | } |
| 49 | |
| 50 | /** |
| 51 | * Add a value to this stackframe |
| 52 | * @param id ID of the value |
| 53 | * @param value The actual value |
| 54 | */ |
| 55 | public void addValue(String id, T value) |
| 56 | { |
| 57 | logger.debug("Value "+value+" added to stackframe under id "+id); |
| 58 | contents.put(id,value); |
| 59 | } |
| 60 | |
| 61 | /** |
| 62 | * Retrieve a value from this stackframe. If the value is not part of this |
| 63 | * stackframe the parent stackframe is queried automatically |
| 64 | * @param id ID of the variable value to retrieve |
| 65 | * @return The value of the variable with id ID. |
| 66 | * @throws ValueNotInFrameException Is throw if this frame and all parent frames |
| 67 | * do not contain the id ID |
| 68 | */ |
| 69 | public T getValue(String id) throws ValueNotInFrameException |
| 70 | { |
| 71 | if (this.contents.containsKey(id)) |
| 72 | return this.contents.get(id); |
| 73 | if (parentFrame != null) |
| 74 | return parentFrame.getValue(id); |
| 75 | throw new ValueNotInFrameException("Identifier "+id+" not found in stackframe!"); |
| 76 | } |
| 77 | |
| 78 | /** |
| 79 | * Clone this stackframe |
| 80 | * @return A clone of the stackframe. The parent frames are copies as well |
| 81 | */ |
| 82 | public SimulatedStackframe<T> copyFrame() |
| 83 | { |
| 84 | SimulatedStackframe<T> copy = new SimulatedStackframe<T>(); |
| 85 | for (String key : this.contents.keySet()) { |
| 86 | copy.addValue(key, contents.get(key)); |
| 87 | } |
| 88 | if (parentFrame != null) |
| 89 | copy.setParentFrame(parentFrame.copyFrame()); |
| 90 | return copy; |
| 91 | } |
| 92 | |
| 93 | private void setParentFrame(SimulatedStackframe<T> frame) { |
| 94 | this.parentFrame = frame; |
| 95 | } |
| 96 | |
| 97 | /** |
| 98 | * @return All IDs and their value in the current frame. For debugging |
| 99 | * and error reporting cases |
| 100 | */ |
| 101 | public ArrayList<Entry<String,T>> getContents() { |
| 102 | return getContentsRecursive(new HashMap<String, T>()); |
| 103 | } |
| 104 | |
| 105 | private ArrayList<Entry<String,T>> getContentsRecursive(HashMap<String,T> alreadyFound) { |
| 106 | ArrayList<Entry<String,T>> result = new ArrayList<Entry<String,T>>(); |
| 107 | for (Entry<String,T> e : contents.entrySet()) { |
| 108 | if (!alreadyFound.containsKey(e.getKey())) { |
| 109 | alreadyFound.put(e.getKey(),e.getValue()); |
| 110 | result.add(e); |
| 111 | } |
| 112 | } |
| 113 | if (parentFrame != null) |
| 114 | result.addAll(parentFrame.getContentsRecursive(alreadyFound)); |
| 115 | return result; |
| 116 | } |
| 117 | |
| 118 | /** |
| 119 | * Add all variables and their values in the given frame to this frame |
| 120 | * @param callResult The frame whose contents will be copied into this frame |
| 121 | */ |
| 122 | public void addVariables(SimulatedStackframe<T> callResult) { |
| 123 | logger.debug("Adding "+callResult.getContents().size()+" value(s) to own stackframe"); |
| 124 | for (Entry<String,T> e : callResult.contents.entrySet()) { |
| 125 | logger.debug("Adding "+e.getKey()+" with "+e.getValue()); |
| 126 | this.addValue(e.getKey(), e.getValue()); |
| 127 | } |
| 128 | |
| 129 | } |
| 130 | |
| 131 | } |