Mercurial > hg > Members > kono > jpf-core
comparison src/main/gov/nasa/jpf/util/script/ScriptEnvironment.java @ 0:61d41facf527
initial v8 import (history reset)
author | Peter Mehlitz <Peter.C.Mehlitz@nasa.gov> |
---|---|
date | Fri, 23 Jan 2015 10:14:01 -0800 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:61d41facf527 |
---|---|
1 /* | |
2 * Copyright (C) 2014, United States Government, as represented by the | |
3 * Administrator of the National Aeronautics and Space Administration. | |
4 * All rights reserved. | |
5 * | |
6 * The Java Pathfinder core (jpf-core) platform is licensed under the | |
7 * Apache License, Version 2.0 (the "License"); you may not use this file except | |
8 * in compliance with the License. You may obtain a copy of the License at | |
9 * | |
10 * http://www.apache.org/licenses/LICENSE-2.0. | |
11 * | |
12 * Unless required by applicable law or agreed to in writing, software | |
13 * distributed under the License is distributed on an "AS IS" BASIS, | |
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 * See the License for the specific language governing permissions and | |
16 * limitations under the License. | |
17 */ | |
18 package gov.nasa.jpf.util.script; | |
19 | |
20 import gov.nasa.jpf.JPF; | |
21 import gov.nasa.jpf.util.StateExtensionClient; | |
22 import gov.nasa.jpf.util.StateExtensionListener; | |
23 import gov.nasa.jpf.vm.ChoiceGenerator; | |
24 | |
25 import java.io.FileNotFoundException; | |
26 import java.io.FileReader; | |
27 import java.io.Reader; | |
28 import java.util.ArrayList; | |
29 import java.util.BitSet; | |
30 import java.util.HashMap; | |
31 import java.util.List; | |
32 | |
33 /** | |
34 * class representing a statemachine environment that produces SCEventGenerators | |
35 * from scripts | |
36 */ | |
37 public abstract class ScriptEnvironment<CG extends ChoiceGenerator<?>> | |
38 implements StateExtensionClient<ScriptEnvironment<CG>.ActiveSnapshot> { | |
39 | |
40 static final String DEFAULT = "default"; | |
41 | |
42 //--- just a helper tuple | |
43 static class ActiveSequence implements Cloneable { | |
44 String stateName; | |
45 Section section; | |
46 SequenceInterpreter intrp; | |
47 | |
48 public ActiveSequence (String stateName, Section section, SequenceInterpreter intrp) { | |
49 this.stateName = stateName; | |
50 this.section = section; | |
51 this.intrp = intrp; | |
52 } | |
53 | |
54 @Override | |
55 public Object clone() { | |
56 try { | |
57 ActiveSequence as = (ActiveSequence) super.clone(); | |
58 as.intrp = (SequenceInterpreter) intrp.clone(); | |
59 return as; | |
60 } catch (CloneNotSupportedException nonsense) { | |
61 return null; // we are a Cloneable, so we don't get here | |
62 } | |
63 } | |
64 | |
65 public boolean isDone() { | |
66 return intrp.isDone(); | |
67 } | |
68 } | |
69 | |
70 //--- our state extension - we need this mostly for cloning (deep copy) | |
71 class ActiveSnapshot implements Cloneable { | |
72 ActiveSequence[] actives; | |
73 | |
74 ActiveSnapshot () { | |
75 actives = new ActiveSequence[0]; | |
76 } | |
77 | |
78 ActiveSnapshot (ActiveSequence[] as) { | |
79 actives = as; | |
80 } | |
81 | |
82 public ActiveSequence get (String stateName) { | |
83 for (ActiveSequence as : actives) { | |
84 if (as.stateName.equals(stateName)) { | |
85 return as; | |
86 } | |
87 } | |
88 return null; | |
89 } | |
90 | |
91 @Override | |
92 public Object clone() { | |
93 try { | |
94 ActiveSnapshot ss = (ActiveSnapshot)super.clone(); | |
95 for (int i=0; i<actives.length; i++) { | |
96 ActiveSequence as = actives[i]; | |
97 ss.actives[i] = (ActiveSequence)as.clone(); | |
98 } | |
99 return ss; | |
100 } catch (CloneNotSupportedException nonsense) { | |
101 return null; // we are a Cloneable, so we don't get here | |
102 } | |
103 } | |
104 | |
105 ActiveSnapshot advance (String[] activeStates, BitSet isReEntered) { | |
106 ActiveSequence[] newActives = new ActiveSequence[activeStates.length]; | |
107 | |
108 //--- carry over the persisting entries | |
109 for (int i=0; i<activeStates.length; i++) { | |
110 String sn = activeStates[i]; | |
111 for (ActiveSequence as : actives) { | |
112 if (as.stateName.equals(sn) ) { | |
113 // we could use isReEntered to determine if we want to restart sequences | |
114 // <2do> how do we factor this out as policy? | |
115 newActives[i] = (ActiveSequence)as.clone(); | |
116 } | |
117 } | |
118 } | |
119 | |
120 //--- add the new ones | |
121 int skipped = 0; | |
122 nextActive: | |
123 for (int i=0; i<activeStates.length; i++) { | |
124 if (newActives[i] == null) { | |
125 // get the script section | |
126 Section sec = getSection(activeStates[i]); | |
127 if (sec != null) { | |
128 | |
129 // check if that section is already processed by another active state, in which case we skip | |
130 for (int j=0; j<newActives.length; j++) { | |
131 if (newActives[j] != null && newActives[j].section == sec) { | |
132 skipped++; | |
133 continue nextActive; | |
134 } | |
135 } | |
136 | |
137 // check if it was processed by a prev state (superstate section by a | |
138 // common parent of a new and an old state - this is the common case | |
139 for (int j=0; j<actives.length; j++) { | |
140 // <2do> how do we handle state re-entering? | |
141 if (actives[j].section == sec) { | |
142 ActiveSequence as = new ActiveSequence(activeStates[i], sec, actives[j].intrp); | |
143 newActives[i] = as; | |
144 continue nextActive; | |
145 } | |
146 } | |
147 | |
148 // it's a new one | |
149 ActiveSequence as = new ActiveSequence(activeStates[i], sec, | |
150 new SequenceInterpreter(sec)); | |
151 newActives[i] = as; | |
152 | |
153 } else { // sec == null : we didn't find any sequence for this state | |
154 skipped++; | |
155 } | |
156 } | |
157 } | |
158 | |
159 //--- compress if we skipped any active states | |
160 if (skipped > 0) { | |
161 int n = activeStates.length - skipped; | |
162 ActiveSequence[] na = new ActiveSequence[n]; | |
163 for (int i=0, j=0; j<n; i++) { | |
164 if (newActives[i] != null) { | |
165 na[j++] = newActives[i]; | |
166 } | |
167 } | |
168 newActives = na; | |
169 } | |
170 | |
171 return new ActiveSnapshot(newActives); | |
172 } | |
173 } | |
174 | |
175 //--- start of ScriptEnvronment | |
176 | |
177 String scriptName; | |
178 Reader scriptReader; | |
179 Script script; | |
180 ActiveSnapshot cur; | |
181 | |
182 HashMap<String,Section> sections = new HashMap<String,Section>(); | |
183 Section defaultSection; | |
184 | |
185 //--- initialization | |
186 public ScriptEnvironment (String fname) throws FileNotFoundException { | |
187 this( fname, new FileReader(fname)); | |
188 } | |
189 | |
190 public ScriptEnvironment (String name, Reader r) { | |
191 this.scriptName = name; | |
192 this.scriptReader = r; | |
193 } | |
194 | |
195 public void parseScript () throws ESParser.Exception { | |
196 ESParser parser= new ESParser(scriptName, scriptReader); | |
197 script = parser.parse(); | |
198 | |
199 initSections(); | |
200 | |
201 cur = new ActiveSnapshot(); | |
202 } | |
203 | |
204 void initSections() { | |
205 Section defSec = new Section(script, DEFAULT); | |
206 | |
207 for (ScriptElement e : script) { | |
208 | |
209 if (e instanceof Section) { | |
210 Section sec = (Section)e; | |
211 List<String> secIds = sec.getIds(); | |
212 if (secIds.size() > 0) { | |
213 for (String id : secIds) { | |
214 sections.put(id, (Section)sec.clone()); // clone to guarantee different identities | |
215 } | |
216 } else { | |
217 sections.put(secIds.get(0), sec); | |
218 } | |
219 } else { // add copy to default sequence | |
220 defSec.add(e.clone()); | |
221 } | |
222 } | |
223 | |
224 if (defSec.getNumberOfChildren() > 0) { | |
225 defaultSection = defSec; | |
226 } | |
227 } | |
228 | |
229 Section getSection (String id) { | |
230 Section sec = null; | |
231 | |
232 while (id != null) { | |
233 sec = sections.get(id); | |
234 if (sec != null) { | |
235 return sec; | |
236 } | |
237 | |
238 int idx = id.lastIndexOf('.'); | |
239 if (idx > 0) { | |
240 id = id.substring(0, idx); // ?? do we really want this recursive? that's policy | |
241 } else { | |
242 id = null; | |
243 } | |
244 } | |
245 | |
246 return defaultSection; | |
247 } | |
248 | |
249 void addExpandedEvent(ArrayList<Event> events, Event se) { | |
250 for (Event e : se.expand()) { | |
251 if (!events.contains(e)) { | |
252 events.add(e); | |
253 } | |
254 } | |
255 } | |
256 | |
257 static final String[] ACTIVE_DEFAULT = { DEFAULT }; | |
258 | |
259 public CG getNext (String id) { | |
260 return getNext(id, ACTIVE_DEFAULT, null); | |
261 } | |
262 | |
263 public CG getNext (String id, String[] activeStates) { | |
264 return getNext(id, activeStates, null); | |
265 } | |
266 | |
267 // this is our main purpose in life, but there is some policy in here | |
268 public CG getNext (String id, String[] activeStates, BitSet isReEntered) { | |
269 | |
270 cur = cur.advance(activeStates, isReEntered); | |
271 | |
272 ArrayList<Event> events = new ArrayList<Event>(cur.actives.length); | |
273 for (ActiveSequence as : cur.actives) { | |
274 | |
275 while (true) { | |
276 ScriptElement se = as.intrp.getNext(); | |
277 if (se != null) { | |
278 if (se instanceof Event) { | |
279 addExpandedEvent(events, (Event)se); | |
280 break; | |
281 } else if (se instanceof Alternative) { | |
282 for (ScriptElement ase : (Alternative)se) { | |
283 if (ase instanceof Event) { | |
284 addExpandedEvent(events, (Event)ase); | |
285 } | |
286 } | |
287 break; | |
288 } else { | |
289 // get next event | |
290 } | |
291 } else { | |
292 break; // process next active sequence | |
293 } | |
294 } | |
295 } | |
296 | |
297 return createCGFromEvents(id, events); | |
298 } | |
299 | |
300 protected abstract CG createCGFromEvents(String id, List<Event> events); | |
301 | |
302 //--- StateExtension interface | |
303 @Override | |
304 public ActiveSnapshot getStateExtension() { | |
305 return cur; | |
306 } | |
307 | |
308 @Override | |
309 public void restore(ActiveSnapshot stateExtension) { | |
310 cur = stateExtension; | |
311 } | |
312 | |
313 @Override | |
314 public void registerListener(JPF jpf) { | |
315 StateExtensionListener<ActiveSnapshot> sel = new StateExtensionListener(this); | |
316 jpf.addSearchListener(sel); | |
317 } | |
318 | |
319 } |