001: /* Copyright 2006 David N. Welton
002:
003: Licensed under the Apache License, Version 2.0 (the "License");
004: you may not use this file except in compliance with the License.
005: You may obtain a copy of the License at
006:
007: http://www.apache.org/licenses/LICENSE-2.0
008:
009: Unless required by applicable law or agreed to in writing, software
010: distributed under the License is distributed on an "AS IS" BASIS,
011: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: See the License for the specific language governing permissions and
013: limitations under the License.
014: */
015:
016: package org.hecl;
017:
018: import java.util.Date;
019: import java.util.Enumeration;
020: import java.util.Hashtable;
021: import java.util.Vector;
022:
023: /**
024: * The <code>InterpCmds</code> implements various Hecl commands that
025: * deal with the state of the interpreter.
026: *
027: * @author <a href="mailto:davidw@dedasys.com">David N. Welton</a>
028: * @version 1.0
029: */
030: class InterpCmds extends Operator {
031: public static final int SET = 1;
032: public static final int UNSET = 2;
033: public static final int PROC = 3;
034: public static final int RENAME = 4;
035: public static final int EVAL = 5;
036: public static final int GLOBAL = 6;
037: public static final int INTROSPECT = 7;
038: public static final int RETURN = 8;
039: public static final int CATCH = 9;
040: public static final int EXIT = 10;
041: public static final int UPCMD = 11;
042: public static final int TIMECMD = 12;
043:
044: public static final int COPY = 13;
045: public static final int THROW = 14;
046: public static final int AFTER = 15;
047: public static final int BGERROR = 16;
048: public static final int TOKENWAIT = 17;
049: public static final int TOKENNOTIFY = 18;
050:
051: protected static final int GC = 19;
052: protected static final int GETPROP = 20;
053: protected static final int HASPROP = 21;
054: protected static final int CLOCKCMD = 22;
055:
056: protected static final int FREEMEM = 23;
057: protected static final int TOTALMEM = 24;
058:
059: public static final int HASCLASS = 70;//Class.forName()
060:
061: public static final int CLASSINFO = 80; // hecl internal!!!
062:
063: public Thing operate(int cmd, Interp interp, Thing[] argv)
064: throws HeclException {
065: Thing result = null;
066: int retval = 0;
067: String subcmd = null;
068:
069: switch (cmd) {
070: case SET:
071: if (argv.length == 3) {
072: interp.setVar(argv[1], argv[2]);
073: return argv[2];
074: }
075: return interp.getVar(argv[1]);
076:
077: case COPY:
078: return argv[1].deepcopy();
079:
080: case UNSET:
081: interp.unSetVar(argv[1]);
082: break;
083:
084: case PROC:
085: interp.commands.put(argv[1].toString(), new Proc(argv[2],
086: argv[3]));
087: break;
088:
089: case RENAME:
090: interp.cmdRename(argv[1].toString(), argv[2].toString());
091: break;
092:
093: case EVAL:
094: return interp.eval(argv[1]);
095:
096: case GLOBAL:
097: ;
098: //#ifdef notdef
099: {
100: String varname = null;
101: Thing newThing = null;
102: for (int i = 1; i < argv.length; i++) {
103: varname = argv[i].toString();
104: newThing = null;
105:
106: if (!interp.existsVar(varname, 0)) {
107: /* Create a new value for it. */
108: newThing = new Thing("");
109: } else {
110: /* If it already exists, make a copy of it
111: * that is no longer marked to be copied. */
112: newThing = interp.getVar(varname, 0);
113: }
114: newThing.global = true;
115: interp.setVar(varname, newThing);
116: interp.setVar(varname, newThing, 0);
117: }
118: break;
119: }
120: //#else
121: for (int i = 1; i < argv.length; i++) {
122: interp.setVar(argv[i].toString(),
123: Interp.GLOBALREFTHING, -1);
124: }
125: //#endif
126: break;
127:
128: case INTROSPECT:
129: subcmd = argv[1].toString();
130: Vector results = new Vector();
131:
132: if (subcmd.equals("commands")) {
133: for (Enumeration e = interp.commands.keys(); e
134: .hasMoreElements();) {
135: Thing t = new Thing((String) e.nextElement());
136: results.addElement(t);
137: }
138: return ListThing.create(results);
139: }
140: if (subcmd.equals("proccode")) {
141: Proc p = (Proc) interp.commands.get(argv[2].toString());
142: return new Thing(p.getCode().getVal());
143: }
144: break;
145:
146: case RETURN:
147: throw new HeclException("", HeclException.RETURN,
148: argv.length > 1 ? argv[1] : Thing.emptyThing());
149:
150: case CATCH:
151: try {
152: result = interp.eval(argv[1]);
153: retval = 0;
154: } catch (HeclException e) {
155: result = e.getStack();
156: retval = 1;
157: }
158:
159: if (argv.length == 3) {
160: interp.setVar(argv[2].toString(),
161: result != null ? result : Thing.emptyThing());
162: }
163: return new Thing(retval != 0 ? IntThing.ONE : IntThing.ZERO);
164:
165: case THROW:
166: String errmsg = argv[1].toString();
167: if (argv.length == 2) {
168: throw new HeclException(errmsg);
169: }
170: throw new HeclException(errmsg, argv[2].toString());
171:
172: case AFTER:
173: subcmd = argv[1].toString();
174: if (subcmd.equals("info")) {
175: if (argv.length == 2) {
176: Vector v = interp.getAllEvents();
177: int n = v.size();
178: for (int i = 0; i < n; ++i) {
179: HeclTask t = (HeclTask) v.elementAt(i);
180: v.setElementAt(new Thing(t.getName()), i);
181: }
182: return ListThing.create(v);
183: }
184: if (argv.length == 3) {
185: String evname = argv[2].toString();
186: HeclTask t = interp.getEvent(evname);
187: // event specified, must exist
188: if (t != null) {
189: Vector v = new Vector();
190: v
191: .addElement(new Thing(t.getScript()
192: .toString()));
193: v.addElement(new Thing(t.getType()));
194: return ListThing.create(v);
195: }
196: throw new HeclException("Event '" + evname
197: + "' doesn't exist.");
198: }
199: throw HeclException.createWrongNumArgsException(argv,
200: 2, "?id?");
201: }
202: if (subcmd.equals("cancel")) {
203: for (int i = 2; i < argv.length; ++i) {
204: String s = argv[2].toString();
205: if (s.startsWith(Interp.IDLEPREFIX))
206: interp.cancelIdle(s);
207: else if (s.startsWith(Interp.TIMERPREFIX))
208: interp.cancelTimer(s);
209: else if (s.startsWith(Interp.ASYNCPREFIX))
210: interp.cancelAsync(s);
211: }
212: break;
213: }
214: if (subcmd.equals("idle")) {
215: if (argv.length != 3)
216: throw HeclException.createWrongNumArgsException(
217: argv, 2, "script");
218: interp.evalIdle(argv[2]);
219: break;
220: }
221: int milli = IntThing.get(argv[1]);
222: if (milli >= 0) {
223: switch (argv.length) {
224: case 3:
225: interp.addTimer(argv[2], milli);
226: break;
227: case 2:
228: ; // fool emacs indentation...
229: {
230: HeclTask t = interp.addTimer(
231: Thing.emptyThing(), milli);
232: while (!t.isDone()) {
233: interp.doOneEvent(Interp.ALL_EVENTS);
234: }
235: }
236: break;
237: default:
238: throw HeclException.createWrongNumArgsException(
239: argv, 2, "script");
240: }
241: break;
242: }
243: throw new HeclException("Unknown after option '" + subcmd
244: + "'.");
245:
246: case TOKENWAIT:
247: subcmd = argv[1].toString(); // varname
248: interp.waitForToken(argv[1].toString());
249: break;
250:
251: case TOKENNOTIFY:
252: interp.notifyToken(argv[1].toString());
253: break;
254:
255: case BGERROR:
256: System.err.println("bgerror - " + argv[1].toString());
257: break;
258:
259: case EXIT:
260: retval = 0;
261: if (argv.length > 1) {
262: retval = IntThing.get(argv[1]);
263: }
264: System.exit(retval);
265: break;
266:
267: case UPCMD:
268: Hashtable save = null;
269: Thing code = null;
270: int level = -1;
271:
272: if (argv.length == 2) {
273: code = argv[1];
274: } else if (argv.length == 3) {
275: code = argv[2];
276: level = IntThing.get(argv[1]);
277: }
278: return interp.eval(code, level);
279:
280: case TIMECMD:
281: int times = 1;
282:
283: if (argv.length > 2) {
284: times = NumberThing.asNumber(argv[2]).intValue();
285: }
286: long then = new Date().getTime();
287: while (times > 0) {
288: interp.eval(argv[1]);
289: times--;
290: }
291: return LongThing.create(new Date().getTime() - then);
292:
293: case HASCLASS:
294: // beware: you may be get fooled in j2me when you use an
295: // obfuscator: custom class names may get changed. Use only for
296: // system-defined classes!
297: retval = 0;
298: try {
299: retval = null != Class.forName(argv[1].toString()) ? 1
300: : 0;
301: } catch (Exception e) {
302: }
303: return IntThing.create(retval);
304:
305: case CLASSINFO:
306: return new Thing("<" + argv[1].getVal().thingclass() + ">");
307:
308: case GC:
309: System.gc();
310: break;
311:
312: case GETPROP:
313: String s = System.getProperty(argv[1].toString());
314: return new Thing(s != null ? s : "");
315:
316: case HASPROP:
317: return IntThing.create(System.getProperty(argv[1]
318: .toString()) != null ? 1 : 0);
319:
320: case CLOCKCMD:
321: subcmd = argv[1].toString();
322: {
323: long l = System.currentTimeMillis();
324: if (subcmd.equals("seconds"))
325: return LongThing.create(l / 1000);
326: if (subcmd.equals("time") || subcmd.equals("milli"))
327: return LongThing.create(l);
328: if (subcmd.equals("format")) {
329: // to bad, j2me does not support DataFormat,
330: if (argv.length == 3)
331: return new Thing(new ListThing((new Date(
332: LongThing.get(argv[2]))).toString()));
333: throw HeclException.createWrongNumArgsException(
334: argv, 2, "?milli?");
335: }
336: throw HeclException.createWrongNumArgsException(argv,
337: 1, "option ?time?");
338: }
339:
340: /*
341: Calendar cal = Calendar.getInstance();
342: cal.setTime(new Date(l));
343:
344: String fmtstr;
345: StringBuffer sb = new StringBuffer();
346: boolean percseen = false;
347: for(int i = 0; i<fmtstr.length(); ++i) {
348: char ch = fmtstr.charAt(i);
349: if(ch == '%') {
350: if(percseen) {
351: sb.append('%');
352: percseen = false;
353: } else
354: percseen = true;
355: continue;
356: }
357:
358: // %a Abbreviated weekday name (Mon, Tue, etc.).
359: // %A Full weekday name (Monday, Tuesday, etc.).
360: // %b Abbreviated month name (Jan, Feb, etc.).
361: // %B Full month name.
362: // %C First two digits of the four-digit year (19 or 20).
363: // %d Day of month (01 - 31).
364: // %D Date as %m/%d/%y.
365: // %e Day of month (1 - 31), no leading zeros.
366: // %h Abbreviated month name.
367: // %H Hour in 24-hour format (00 - 23).
368: // %I Hour in 12-hour format (01 - 12).
369: // %j Day of year (001 - 366).
370: // %k Hour in 24-hour format, without leading zeros (0 - 23).
371: // %l Hour in 12-hour format, without leading zeros (1 - 12).
372: // %m Month number (01 - 12).
373: // %M Minute (00 - 59).
374: // %n Insert a newline.
375: // %p AM/PM indicator.
376: // %R Time as %H:%M.
377: // %s Count of seconds since the epoch, expressed as a decimal integer.
378: // %S Seconds (00 - 59).
379: // %t Insert a tab.
380: // %T Time as %H:%M:%S.
381: // %u Weekday number (Monday = 1, Sunday = 7).
382: // %U Week of year (00 - 52), Sunday is the first day of the week.
383: // %V Week of year according to ISO-8601 rules. Week 1 of a given year is the
384: // week containing 4 January.
385: // %w Weekday number (Sunday = 0, Saturday = 6).
386: // %W Week of year (00 - 52), Monday is the first day of the week.
387: // %y Year without century (00 - 99).
388: // %Y Year with century (e.g. 1990)
389: // %Z Time zone name.
390: switch(ch) {
391: case 'a':
392: sb.append(cal.get(Calendar.
393: default:
394: sb.append(ch);
395: }
396: }
397: return new StringThing(sb);
398: */
399: case FREEMEM:
400: return LongThing.create(Runtime.getRuntime().freeMemory());
401:
402: case TOTALMEM:
403: return LongThing.create(Runtime.getRuntime().totalMemory());
404:
405: default:
406: throw new HeclException("Unknown interp command '"
407: + argv[0].toString() + "' with code '" + cmd + "'.");
408: }
409: return null;
410: }
411:
412: public static void load(Interp ip) throws HeclException {
413: Operator.load(ip, cmdtable);
414: }
415:
416: public static void unload(Interp ip) throws HeclException {
417: Operator.unload(ip, cmdtable);
418: }
419:
420: private InterpCmds(int cmdcode, int minargs, int maxargs) {
421: super (cmdcode, minargs, maxargs);
422: }
423:
424: private static Hashtable cmdtable = new Hashtable();
425:
426: static {
427: cmdtable.put("set", new InterpCmds(SET, 1, 2));
428: cmdtable.put("unset", new InterpCmds(UNSET, 1, 1));
429: cmdtable.put("proc", new InterpCmds(PROC, 3, 3));
430: cmdtable.put("rename", new InterpCmds(RENAME, 2, 2));
431: cmdtable.put("eval", new InterpCmds(EVAL, 1, 1));
432: cmdtable.put("global", new InterpCmds(GLOBAL, 0, -1));
433: cmdtable.put("intro", new InterpCmds(INTROSPECT, 1, -1));
434: cmdtable.put("return", new InterpCmds(RETURN, 0, 1));
435: cmdtable.put("catch", new InterpCmds(CATCH, 1, 2));
436: cmdtable.put("throw", new InterpCmds(THROW, 1, 2));
437: cmdtable.put("exit", new InterpCmds(EXIT, 0, 1));
438: cmdtable.put("upeval", new InterpCmds(UPCMD, 1, 2));
439: cmdtable.put("time", new InterpCmds(TIMECMD, 1, 2));
440: cmdtable.put("after", new InterpCmds(AFTER, 1, -1));
441: cmdtable.put("bgerror", new InterpCmds(BGERROR, 1, 1));
442: cmdtable.put("twait", new InterpCmds(TOKENWAIT, 1, 1));
443: cmdtable.put("tnotify", new InterpCmds(TOKENNOTIFY, 1, 1));
444:
445: cmdtable.put("copy", new InterpCmds(COPY, 1, 1));
446:
447: cmdtable.put("system.gc", new InterpCmds(GC, 0, 0));
448: cmdtable.put("system.getproperty",
449: new InterpCmds(GETPROP, 1, 1));
450: cmdtable.put("system.hasproperty",
451: new InterpCmds(HASPROP, 1, 1));
452: cmdtable.put("clock", new InterpCmds(CLOCKCMD, 1, 2));
453:
454: cmdtable.put("runtime.freememory",
455: new InterpCmds(FREEMEM, 0, 0));
456: cmdtable.put("runtime.totalmemory", new InterpCmds(TOTALMEM, 0,
457: 0));
458:
459: cmdtable.put("hasclass", new InterpCmds(HASCLASS, 1, 1));
460:
461: cmdtable.put("classof", new InterpCmds(CLASSINFO, 1, 1));
462: }
463: }
|