1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package net.sf.zel.vm;
19
20 import java.io.BufferedReader;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.InputStreamReader;
24 import java.io.PrintStream;
25 import java.io.Serializable;
26 import java.util.Arrays;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.concurrent.Callable;
30 import java.util.concurrent.ExecutionException;
31 import java.util.concurrent.Future;
32 import java.util.concurrent.ThreadPoolExecutor;
33 import java.util.concurrent.TimeUnit;
34 import java.util.concurrent.TimeoutException;
35 import javax.annotation.CheckReturnValue;
36 import javax.annotation.Nonnull;
37 import javax.annotation.Nonnegative;
38 import javax.annotation.Nullable;
39 import javax.annotation.concurrent.Immutable;
40 import net.sf.zel.instr.Instruction;
41 import net.sf.zel.math.ExtendedMathContext;
42
43
44
45
46
47
48
49
50 @Immutable
51 public final class Program implements Serializable
52 {
53
54 public enum Type
55 {
56
57 DETERMINISTIC, NONDETERMINISTIC
58 };
59 static final long serialVersionUID = 748365748433474932L;
60 private final Type type;
61 private final int id;
62 private final Object[] instructions;
63 private final ExtendedMathContext mathContext;
64
65
66
67
68
69 public Program(@Nonnull final Object[] objs, @Nonnegative final int start,
70 @Nonnegative final int end, final Type progType,
71 @Nonnull final ExtendedMathContext mathContext)
72 {
73 int length = end - start;
74 instructions = new Object[length];
75 System.arraycopy(objs, start, instructions, 0, length);
76 this.type = progType;
77 id = ProgramBuilder.generateID();
78 this.mathContext = mathContext;
79 }
80
81 @Override
82 @CheckReturnValue
83 public boolean equals(@Nullable final Object obj)
84 {
85 if (obj == null)
86 {
87 return false;
88 }
89 if (getClass() != obj.getClass())
90 {
91 return false;
92 }
93 final Program other = (Program) obj;
94 if (this.id != other.id)
95 {
96 return false;
97 }
98 return true;
99 }
100
101 @Override
102 @CheckReturnValue
103 public int hashCode()
104 {
105 int hash = 7;
106 hash = 79 * hash + this.id;
107 return hash;
108 }
109
110
111
112
113 @CheckReturnValue
114 public Object get(final int i)
115 {
116 return instructions[i];
117 }
118
119 @CheckReturnValue
120 Object[] toArray()
121 {
122 return instructions.clone();
123 }
124
125 @CheckReturnValue
126 public int size()
127 {
128 return instructions.length;
129 }
130
131 public static Program compile(@Nonnull final String zExpr,
132 @Nonnull final ExtendedMathContext mc,
133 @Nonnull String... varNames)
134 throws ParseException
135 {
136 ExtendedMathContext.CURRENT_EXTENDED_MATH_CONTEXT.set(mc);
137 return compile(zExpr, varNames);
138 }
139
140
141
142
143
144
145
146 public static Program compile(@Nonnull final String zExpr, @Nonnull String... varNames) throws ParseException
147 {
148
149 CompileContext cc = new CompileContext();
150 try
151 {
152 ZCompiler.compile(zExpr, cc, varNames);
153 }
154
155 catch (TokenMgrError err)
156 {
157 ParseException te = new ParseException(err.getMessage());
158 te.setStackTrace(err.getStackTrace());
159 throw te;
160 }
161 return cc.getProgramBuilder().toProgram();
162
163 }
164
165 public Object execute() throws ZExecutionException
166 {
167 return execute(newMem(), null, null, null);
168 }
169
170 public Object execute(Object... args) throws ZExecutionException
171 {
172 return execute(newMem(), null, null, null, args);
173 }
174
175
176
177
178
179
180
181 public Object execute(@Nonnull java.util.Map memory, Object... args) throws ZExecutionException
182 {
183 return execute(memory, null, null, null, args);
184 }
185
186
187
188
189
190
191
192
193
194
195
196
197 public Object executeInterruptibly(@Nonnull final java.util.Map memory, @Nonnull final InputStream in,
198 @Nonnull final PrintStream out, @Nonnull final PrintStream err, ThreadPoolExecutor execService, Object... args)
199 throws ZExecutionException, InterruptedException
200 {
201 ExtendedMathContext.CURRENT_EXTENDED_MATH_CONTEXT.set(this.mathContext);
202 ExecutionContext ectx = new ExecutionContext(this, memory, in, out, err, execService);
203 ectx.stack.pushAll(args);
204 while (!ectx.terminated)
205 {
206 try
207 {
208 ((Instruction) ectx.code.instructions[ectx.ip]).execute(ectx);
209 } catch (Exception e)
210 {
211
212 throw new ZExecutionException("Exception detected while running program", e, ectx);
213 }
214
215 if (Thread.interrupted())
216 {
217 throw new InterruptedException("Program execution Interrupted");
218 }
219 }
220 return ectx.stack.pop();
221 }
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237 public Object execute(@Nonnull final java.util.Map memory, @Nonnull final InputStream in,
238 @Nonnull final PrintStream out, @Nonnull final PrintStream err, ThreadPoolExecutor execService, Object... args)
239 throws ZExecutionException
240 {
241 ExtendedMathContext.CURRENT_EXTENDED_MATH_CONTEXT.set(this.mathContext);
242 final ExecutionContext ectx = new ExecutionContext(this, memory, in, out, err, execService);
243 ectx.stack.pushAll(args);
244 return execute(ectx);
245 }
246
247 public static Object execute(@Nonnull final ExecutionContext ectx)
248 throws ZExecutionException
249 {
250 final Callable<Object> execution = new Callable<Object>()
251 {
252
253 @Override
254 public Object call() throws ExecutionException
255 {
256 while (!ectx.terminated)
257 {
258 try
259 {
260 Object code = ectx.code.instructions[ectx.ip];
261 if (code instanceof Instruction)
262 {
263 ((Instruction) code).execute(ectx);
264 } else
265 {
266 ectx.stack.push(ectx.code.instructions[ectx.ip++]);
267 }
268 } catch (Exception e)
269 {
270
271 throw new ZExecutionException("Exception detected while running program", e, ectx);
272 }
273 }
274 if (!ectx.stack.isEmpty())
275 {
276 return ectx.stack.pop();
277 } else
278 {
279 return null;
280 }
281 }
282 };
283 if (ectx.execService != null)
284 {
285 if (ectx.execService.getActiveCount() < ectx.execService.getPoolSize())
286 {
287 return ectx.execService.submit(execution);
288 } else
289 {
290 return new Future()
291 {
292
293 @Override
294 public boolean cancel(boolean mayInterruptIfRunning)
295 {
296 throw new UnsupportedOperationException("Not supported yet.");
297 }
298
299 @Override
300 public boolean isCancelled()
301 {
302 return false;
303 }
304
305 @Override
306 public boolean isDone()
307 {
308 return true;
309 }
310
311 @Override
312 public Object get() throws InterruptedException, ExecutionException
313 {
314 try
315 {
316 return execution.call();
317 } catch (Exception ex)
318 {
319 throw new ExecutionException(ex);
320 }
321 }
322
323 @Override
324 public Object get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
325 {
326 try
327 {
328 return execution.call();
329 } catch (Exception ex)
330 {
331 throw new ExecutionException(ex);
332 }
333 }
334 };
335 }
336 } else
337 {
338 try
339 {
340 return execution.call();
341 } catch (Exception ex)
342 {
343 throw new ZExecutionException(ex);
344 }
345 }
346
347 }
348
349 public Object execute(@Nonnull final java.util.Map memory, @Nonnull final InputStream in,
350 @Nonnull final PrintStream out, @Nonnull final PrintStream err, Object... args)
351 throws ZExecutionException
352 {
353 return execute(memory, in, out, err, null, args);
354 }
355
356
357
358
359
360
361
362
363 public java.util.Set<Variable> getDependencySet(@Nonnull String expr) throws Exception
364 {
365 ProcDepContext pc = new ProcDepContext();
366 ZCompiler.compile(expr, pc, null);
367 return pc.getDependencySet();
368 }
369
370 @CheckReturnValue
371 @Nonnull
372 public static java.util.Map newMem()
373 {
374
375
376 return new Memory();
377 }
378
379
380
381
382
383
384
385
386
387 @SuppressWarnings("unchecked")
388 public static void linkMem(@Nonnull java.util.Map mem, @Nonnull String name, java.util.Map mem2)
389 throws ParseException, ZExecutionException
390 {
391 final List tokens = ZCompiler.getReference(name);
392 java.util.Map ctx = mem;
393 int i = 0;
394 for (; i < tokens.size() - 1; i++)
395 {
396 final Object token = tokens.get(i);
397 Map nctx = null;
398 Object tmpObj = ctx.get(token);
399 if (!(tmpObj instanceof Map))
400 {
401 StringBuilder parsedVar = new StringBuilder(tokens.get(0).toString());
402 for (int u = 1; u < i + 1; u++)
403 {
404 parsedVar.append("." + tokens.get(u).toString());
405 }
406 throw new ZExecutionException("Cannot change type of existing variable "
407 + parsedVar + " = " + ctx.get(token) + " to structure type ");
408 }
409 nctx = (Map) tmpObj;
410 if (nctx == null)
411 {
412 nctx = newMem();
413 ctx.put(token, nctx);
414 }
415 ctx = nctx;
416 }
417 ctx.put(tokens.get(i), mem2);
418 }
419
420
421
422
423
424
425
426
427
428 public static Object getValue(@Nonnull java.util.Map mem, @Nonnull String name)
429 throws ParseException, ZExecutionException
430 {
431 return Program.compile(name + ";").execute(mem);
432 }
433
434
435
436
437
438
439
440
441
442 public static void addValue(@Nonnull java.util.Map mem, @Nonnull String name,
443 Object value, @Nonnull ExtendedMathContext mc) throws ParseException, ZExecutionException
444 {
445 Program.compile(name + "=" + value + ";", mc).execute(mem);
446 }
447
448
449
450
451
452
453 @CheckReturnValue
454 public static String strIndent(@Nonnegative int indent)
455 {
456 StringBuilder result = new StringBuilder();
457 for (int i = 0; i < indent; i++)
458 {
459 result.append(' ');
460 }
461 return result.toString();
462 }
463
464
465
466
467
468
469
470
471
472 @SuppressWarnings("unchecked")
473 @CheckReturnValue
474 public static String dumpCore(String name, Object mem, int indent, int maxIndent)
475 {
476 if (mem == null)
477 {
478 return "";
479 }
480 if (maxIndent > 0 && indent > maxIndent)
481 {
482 return "";
483 }
484 StringBuilder result = new StringBuilder();
485 if (mem instanceof java.util.Map)
486 {
487 result.append(strIndent(indent)).append(name).append('\n');
488 for (Map.Entry<Object, Object> elem : ((Map<Object, Object>) mem).entrySet())
489 {
490 result.append(dumpCore(elem.getKey().toString(), elem.getValue(), indent + 1, maxIndent));
491 }
492 } else
493 {
494 result.append(strIndent(indent)).append(name).append('=').append(mem.toString()).append('\n');
495 }
496 return result.toString();
497 }
498
499
500
501
502
503 public static void main(final String[] args) throws IOException
504 {
505 System.out.println("ZEL Shell");
506 boolean terminated = false;
507 Memory mem = new Memory();
508 InputStreamReader inp = new InputStreamReader(System.in);
509 BufferedReader br = new BufferedReader(inp);
510 while (!terminated)
511 {
512 System.out.print("zel>");
513 String line = br.readLine();
514 if (line.toUpperCase().startsWith("QUIT"))
515 {
516 terminated = true;
517 } else
518 {
519 try
520 {
521 Program.compile(line).execute(mem, System.in, System.out, System.err);
522 } catch (ParseException ex)
523 {
524 System.out.println("Syntax Error: " + ex.getMessage());
525 } catch (ExecutionException ex)
526 {
527 System.out.println("Execution Error: " + ex.getMessage());
528 }
529 }
530 }
531 }
532
533 @Override
534 public String toString()
535 {
536 return "Program: " + Arrays.toString(instructions);
537 }
538
539
540
541
542 public Program.Type getType()
543 {
544 return type;
545 }
546 }