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 }