From 0003745a6cb4e82b5d1225c926f508bddf9913bb Mon Sep 17 00:00:00 2001 From: megacz Date: Fri, 30 Jan 2004 06:59:55 +0000 Subject: [PATCH] 2003/05/06 09:05:49 darcs-hash:20040130065955-2ba56-7d730002f599aa834a397dce388c272093ef97fb.gz --- src/org/xwt/js/Expr.java | 302 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 302 insertions(+) create mode 100644 src/org/xwt/js/Expr.java diff --git a/src/org/xwt/js/Expr.java b/src/org/xwt/js/Expr.java new file mode 100644 index 0000000..7f5df62 --- /dev/null +++ b/src/org/xwt/js/Expr.java @@ -0,0 +1,302 @@ +// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +package org.xwt.js; + +import java.io.*; +import org.xwt.util.*; + +/** sorta like gcc trees */ +public class Expr { + int code = -1; + + final Expr left; + final Expr right; + Expr next = null; // if this expr is part of a list + + String string = null; + Number number = null; + + public String toString() { return toString(0); } + public String toString(int indent) { + String ret = ""; + for(int i=0; i> toLong(right.eval(s))); + case Lexer.URSH: return new Long(toLong(left.eval(s)) >>> toLong(right.eval(s))); + + case Lexer.LT: return toDouble(left.eval(s)) < toDouble(right.eval(s)) ? Boolean.TRUE : Boolean.FALSE; + case Lexer.LE: return toDouble(left.eval(s)) <= toDouble(right.eval(s)) ? Boolean.TRUE : Boolean.FALSE; + case Lexer.GT: return toDouble(left.eval(s)) > toDouble(right.eval(s)) ? Boolean.TRUE : Boolean.FALSE; + case Lexer.GE: return toDouble(left.eval(s)) >= toDouble(right.eval(s)) ? Boolean.TRUE : Boolean.FALSE; + + case Lexer.OR: return new Boolean(toBoolean(left.eval(s)) || toBoolean(right.eval(s))); + case Lexer.AND: return new Boolean(toBoolean(left.eval(s)) && toBoolean(right.eval(s))); + + case Lexer.EQ: + case Lexer.NE: { + // FIXME: should use Javascript coercion-equality rules + boolean ret = left.eval(s).equals(right.eval(s)); + return new Boolean(code == Lexer.EQ ? ret : !ret); + } + + case Lexer.INC: + case Lexer.DEC: + case Lexer.ASSIGN: { + Object v = (code == Lexer.ASSIGN) ? right.eval(s) : new Double(toDouble(left.eval(s)) + (code == Lexer.INC ? 1 : -1)); + if (left.code == Lexer.DOT) { + Object o = left.left.eval(s); + if (o instanceof String) { + throw new Error("can't set properties on a String"); + } else if (o instanceof Number) { + throw new Error("can't set properties on a Number"); + } else if (o instanceof Boolean) { + throw new Error("can't set properties on a Boolean"); + } else { + ((JS)left.left.eval(s)).put(left.right.eval(s), v); + return v; + } + } else { + s.put(left.string, v); + return v; + } + } + + case Lexer.TYPEOF: { + Object o = left.eval(s); + if (o == null) return "null"; + if (o.getClass() == String.class) return "string"; + if (o.getClass() == Boolean.class) return "boolean"; + if (o instanceof Number) return "number"; + if (o instanceof JS.Array) return "array"; + if (o instanceof JS) return "object"; + throw new Error("typeof " + o.getClass().getName() + " unknown"); + } + + case Lexer.NUMBER: return number; + case Lexer.STRING: return string; + + case Lexer.NULL: return null; + case Lexer.THIS: return s; + case Lexer.FALSE: return Boolean.FALSE; + case Lexer.TRUE: return Boolean.TRUE; + case Lexer.ASSERT: if (!toBoolean(left.eval(s))) throw new Error("assertion failed"); + case Lexer.THROW: throw new JS.Exn(left.eval(s)); + + case Lexer.NAME: return s.get(string); + case Lexer.DOT: { + Object o = left.eval(s); + Object v = right.eval(s); + if (o instanceof String) { + if (v.equals("length")) return new Integer(((String)o).length()); + throw new Error("Not Implemented: properties on String objects"); + } else if (o instanceof Boolean) { + throw new Error("Not Implemented: properties on Boolean objects"); + } else if (o instanceof Number) { + throw new Error("Not Implemented: properties on Number objects"); + } else if (o instanceof JS) { + return ((JS)o).get(v); + } + } + + case Lexer.TRY: { + boolean safeToExit = false; + try { + Object ret = left.eval(s); + safeToExit = true; + return ret; + } catch (JS.Exn e) { + Expr c = right; + if (c.code == Lexer.CATCH) { + JS.Scope scope = new JS.Scope(s); + s.put(c.left.string, e); + c.right.eval(scope); + c = c.next; + } + if (c.code == Lexer.FINALLY) { + JS.Scope scope = new JS.Scope(s); + c.left.eval(scope); + } + } finally { + if (!safeToExit) Log.log(this, "WARNING: Java exception penetrated a JavaScript try{} block"); + } + return null; + } + + case Lexer.LP: + JS.Function f = (JS.Function)left.eval(s); + JS.Array arguments = new JS.Array(); + for(Expr e = right; e != null; e = e.next) arguments.addElement(e.eval(s)); + return f.call(arguments); + + case Lexer.FUNCTION: + return new JS.ObjFunction() { + public JS.Scope getParentScopeOfDeclaration() { return s; } + public Object call(JS.Array args) throws JS.Exn { + JS.Scope scope = new JS.Scope(getParentScopeOfDeclaration()) { + public Object get(Object key) throws JS.Exn { + if (key.equals("trapee")) return org.xwt.Trap.currentTrapee(); + return super.get(key); + } + } + // FIXME + args.put("cascade", org.xwt.Trap.cascadeFunction); + scope.put("arguments", args); + int i = 0; + for(Expr e = left; e != null; e = e.next) scope.put(e.string, args.get(new Integer(i++))); + try { + return right.eval(scope); + } catch (ReturnException r) { + return r.retval; + } catch (ControlTransferException c) { + throw new Error("error, ControlTransferException tried to leave a function: " + c); + } + } + }; + + case Lexer.FOR: + Object[] keys = ((JS)left.right.eval(s)).enumerateProperties(); + try { + for(int i=0; i