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 | } |