From 719959353e804f0f9f5dc08b464a61c53cecb88c Mon Sep 17 00:00:00 2001 From: hns Date: Fri, 29 Nov 2002 17:56:44 +0000 Subject: [PATCH] Merged in changes from FESI 1.1.5 --- src/FESI/Data/ESArguments.java | 8 +- .../EcmaScriptEvaluateVisitor.java | 117 +++++++++++------- src/FESI/Interpreter/FesiHashtable.java | 2 +- src/FESI/Parser/EcmaScript.java | 16 +-- src/FESI/Parser/EcmaScriptTokenManager.java | 7 ++ 5 files changed, 95 insertions(+), 55 deletions(-) diff --git a/src/FESI/Data/ESArguments.java b/src/FESI/Data/ESArguments.java index 65cb287e..b4fe217c 100644 --- a/src/FESI/Data/ESArguments.java +++ b/src/FESI/Data/ESArguments.java @@ -185,11 +185,15 @@ public final class ESArguments extends ESObject { ESValue[] argumentValues) { ObjectPrototype op = (ObjectPrototype) evaluator.getObjectPrototype(); + // Get maximum number of arguments (formal or actual), as + // more than the number of formal arguments can be reached + // using the (old fashioned) arguments variable). + int maxArgs = Math.max(argumentValues.length, argumentNames.length); ESArguments args = new ESArguments(op, evaluator, argumentNames, - Math.max(argumentValues.length, argumentNames.length), + maxArgs, callee); try { - for (int i=0; i2) { throw new ProgrammingError("Bad AST in variable declaration"); } - Object result = null; if (nChildren == 2) { try { Object lvo = node.jjtGetChild(0).jjtAccept(this,FOR_REFERENCE); @@ -376,7 +376,7 @@ public class EcmaScriptEvaluateVisitor throw new ProgrammingError("Bad AST in IF statement"); } try { - ESValue testValue = (ESValue) node.jjtGetChild(0).jjtAccept(this, FOR_VALUE); + ESValue testValue = acceptNull(node.jjtGetChild(0).jjtAccept(this, FOR_VALUE)); boolean test = testValue.booleanValue(); if (test) { result = node.jjtGetChild(1).jjtAccept(this,FOR_VALUE); @@ -395,7 +395,7 @@ public class EcmaScriptEvaluateVisitor Object result = null; node.assertTwoChildren(); try { - ESValue testValue = (ESValue) node.jjtGetChild(0).jjtAccept(this,FOR_VALUE); + ESValue testValue = acceptNull(node.jjtGetChild(0).jjtAccept(this,FOR_VALUE)); while (testValue.booleanValue()) { // Thread.yield (); @@ -406,13 +406,13 @@ public class EcmaScriptEvaluateVisitor if (completionCode == C_RETURN) { return result; } else if (completionCode == C_BREAK) { - completionCode = C_NORMAL; + completionCode = C_NORMAL; return result; } else if (completionCode == C_CONTINUE) { - testValue = (ESValue) node.jjtGetChild(0).jjtAccept(this,FOR_VALUE); + testValue = acceptNull(node.jjtGetChild(0).jjtAccept(this,FOR_VALUE)); completionCode = C_NORMAL; } else { - testValue = (ESValue) node.jjtGetChild(0).jjtAccept(this,FOR_VALUE); + testValue = acceptNull(node.jjtGetChild(0).jjtAccept(this,FOR_VALUE)); } } } catch (EcmaScriptException e) { @@ -433,7 +433,7 @@ public class EcmaScriptEvaluateVisitor if (testNode instanceof ASTEmptyExpression) { testValue = ESBoolean.makeBoolean(true); } else { - testValue = (ESValue) testNode.jjtAccept(this,FOR_VALUE); + testValue = acceptNull(testNode.jjtAccept(this,FOR_VALUE)); } while (testValue.booleanValue()) { // Thread.yield (); @@ -452,7 +452,7 @@ public class EcmaScriptEvaluateVisitor if (testNode instanceof ASTEmptyExpression) { testValue = ESBoolean.makeBoolean(true); } else { - testValue = (ESValue) testNode.jjtAccept(this,FOR_VALUE); + testValue = acceptNull(testNode.jjtAccept(this,FOR_VALUE)); } completionCode = C_NORMAL; } else { @@ -460,7 +460,7 @@ public class EcmaScriptEvaluateVisitor if (testNode instanceof ASTEmptyExpression) { testValue = ESBoolean.makeBoolean(true); } else { - testValue = (ESValue) testNode.jjtAccept(this,FOR_VALUE); + testValue = acceptNull(testNode.jjtAccept(this,FOR_VALUE)); } } @@ -483,7 +483,7 @@ public class EcmaScriptEvaluateVisitor if (testNode instanceof ASTEmptyExpression) { testValue = ESBoolean.makeBoolean(true); } else { - testValue = (ESValue) testNode.jjtAccept(this,FOR_VALUE); + testValue = acceptNull(testNode.jjtAccept(this,FOR_VALUE)); } while (testValue.booleanValue()) { result = node.jjtGetChild(3).jjtAccept(this,FOR_VALUE); @@ -498,7 +498,7 @@ public class EcmaScriptEvaluateVisitor if (testNode instanceof ASTEmptyExpression) { testValue = ESBoolean.makeBoolean(true); } else { - testValue = (ESValue) testNode.jjtAccept(this,FOR_VALUE); + testValue = acceptNull(testNode.jjtAccept(this,FOR_VALUE)); } completionCode = C_NORMAL; } else { @@ -506,18 +506,18 @@ public class EcmaScriptEvaluateVisitor if (testNode instanceof ASTEmptyExpression) { testValue = ESBoolean.makeBoolean(true); } else { - testValue = (ESValue) testNode.jjtAccept(this,FOR_VALUE); + testValue = acceptNull(testNode.jjtAccept(this,FOR_VALUE)); } } // Thread.yield (); if (evaluator.thread != Thread.currentThread()) throw new helma.framework.TimeoutException(); - + } } catch (EcmaScriptException e) { throw new PackagedException(e,node); - } + } return result; } @@ -525,7 +525,7 @@ public class EcmaScriptEvaluateVisitor Object result = null; // No value by default node.assertThreeChildren(); try { - ESValue ob = (ESValue) node.jjtGetChild(1).jjtAccept(this,FOR_VALUE); + ESValue ob = acceptNull(node.jjtGetChild(1).jjtAccept(this,FOR_VALUE)); ESObject obj = (ESObject) ob.toESObject(evaluator); boolean directEnumeration = obj.isDirectEnumerator(); for (Enumeration e = obj.getProperties() ; e.hasMoreElements() ;) { @@ -576,10 +576,10 @@ public class EcmaScriptEvaluateVisitor // Should not happen as it should be an identifier throw new ProgrammingError("Value '"+lvo.toString()+"' is not a variable"); } - ESValue init = (ESValue) node.jjtGetChild(1).jjtAccept(this, FOR_VALUE); + ESValue init = acceptNull(node.jjtGetChild(1).jjtAccept(this, FOR_VALUE)); evaluator.putValue(lv, init); - ESValue ob = (ESValue) node.jjtGetChild(2).jjtAccept(this,FOR_VALUE); + ESValue ob = acceptNull(node.jjtGetChild(2).jjtAccept(this,FOR_VALUE)); ESObject obj = (ESObject) ob.toESObject(evaluator); boolean directEnumeration = obj.isDirectEnumerator(); for (Enumeration e = obj.getProperties() ; e.hasMoreElements() ;) { @@ -635,7 +635,7 @@ public class EcmaScriptEvaluateVisitor ESValue result = null; try { EvaluationSource es = (EvaluationSource) node.getEvaluationSource(); - ESValue scopeValue = (ESValue) node.jjtGetChild(0).jjtAccept(this,FOR_VALUE); + ESValue scopeValue = acceptNull(node.jjtGetChild(0).jjtAccept(this,FOR_VALUE)); ASTStatement statementNode = (ASTStatement) (node.jjtGetChild(1)); ESObject scopeObject = (ESObject) scopeValue.toESObject(evaluator); result = evaluator.evaluateWith(statementNode, scopeObject, es); @@ -679,7 +679,7 @@ public class EcmaScriptEvaluateVisitor String id = ((ASTIdentifier)baseNode).getName(); currentProperty = new ESString(id); } else { - lastResult = (ESValue) baseNode.jjtAccept(this,FOR_VALUE); + lastResult = acceptNull(baseNode.jjtAccept(this,FOR_VALUE)); currentProperty = null; // No reference so far } } @@ -811,7 +811,10 @@ public class EcmaScriptEvaluateVisitor //System.out.println("--->Build value cp: " + currentProperty + " lr: " + lastResult + "<---"); // ******** if (currentProperty != null) { // Must dereference value - ESObject currentBase = (ESObject) lastResult.toESObject(evaluator); + if (lastResult == null) { + throw new EcmaScriptException("'undefined' is not an object with properties"); + } + ESObject currentBase = (ESObject) lastResult.toESObject(evaluator); String propertyName = currentProperty.toString(); //System.out.println("--->getProperty in cb: " + currentBase + " pn: " + propertyName + "<---"); // ******* result = currentBase.getProperty(propertyName,propertyName.hashCode()); @@ -822,6 +825,9 @@ public class EcmaScriptEvaluateVisitor } else { // We want a reference - therefore it cannot be just a value, it // must be a delayed reference. + if (lastResult == null) { + throw new EcmaScriptException("'undefined' is not an assignable value"); + } if (currentProperty == null) { throw new EcmaScriptException("'"+lastResult.toString()+"' is not an assignable value"); } @@ -850,7 +856,7 @@ public class EcmaScriptEvaluateVisitor public Object visit(ASTPropertyValueReference node, Object data) { node.assertOneChild(); - return node.jjtGetChild(0).jjtAccept(this, FOR_VALUE); + return acceptNull(node.jjtGetChild(0).jjtAccept(this, FOR_VALUE)); } public Object visit(ASTPropertyIdentifierReference node, Object data) { @@ -872,7 +878,8 @@ public class EcmaScriptEvaluateVisitor try { int nChildren=node.jjtGetNumChildren(); Node baseNode = node.jjtGetChild(0); - ESValue constr = (ESValue) baseNode.jjtAccept(this, FOR_VALUE); // Can be any expression (in fact a a.b.c sequence) + // Can be any expression (in fact a a.b.c sequence) [code bizare here] + ESValue constr = acceptNull(baseNode.jjtAccept(this, FOR_VALUE)); Node compositor = node.jjtGetChild(1); if (compositor instanceof ASTFunctionCallParameters) { ASTFunctionCallParameters fc = (ASTFunctionCallParameters) compositor; @@ -956,7 +963,8 @@ public class EcmaScriptEvaluateVisitor if (n instanceof ASTIdentifier) { // We need to get a reference, as an null based referenced is "undefined" ESReference ref = (ESReference) n.jjtAccept(this,FOR_REFERENCE); - if (ref.getBase()==null) { + // If reference to nothing, consider undefined + if (ref == null || ref.getBase()==null) { r = new ESString("undefined"); } else { ESValue v = ref.getValue(); @@ -964,7 +972,7 @@ public class EcmaScriptEvaluateVisitor } } else { // It is a value, directly get its string - ESValue v = (ESValue) n.jjtAccept(this,FOR_VALUE); + ESValue v = acceptNull(n.jjtAccept(this,FOR_VALUE)); r = new ESString(v.getTypeofString()); } } @@ -1035,9 +1043,9 @@ public class EcmaScriptEvaluateVisitor public Object visit(ASTBinaryExpressionSequence node, Object data) { ESValue result = null; try { - ESValue v1 = (ESValue) node.jjtGetChild(0).jjtAccept(this,FOR_VALUE); + ESValue v1 = acceptNull(node.jjtGetChild(0).jjtAccept(this,FOR_VALUE)); for (int i = 0; i < node.jjtGetNumChildren()-1; i+=2) { - ESValue v2 = (ESValue) node.jjtGetChild(i+2).jjtAccept(this,FOR_VALUE); + ESValue v2 = acceptNull(node.jjtGetChild(i+2).jjtAccept(this,FOR_VALUE)); int operator = ((ASTOperator)(node.jjtGetChild(i+1))).getOperator(); // System.out.println("V1 = " + v1 + " v2 = " + v2); switch (operator) { @@ -1168,10 +1176,10 @@ public class EcmaScriptEvaluateVisitor ESValue result = null; int nChildren = node.jjtGetNumChildren(); try { - result = (ESValue) node.jjtGetChild(0).jjtAccept(this,FOR_VALUE); + result = acceptNull(node.jjtGetChild(0).jjtAccept(this,FOR_VALUE)); int i = 1; while (result.booleanValue() && (iAn alternative would be to return ESUndefined in all cases, + * but then we lose a useful distinction (at least for debugging...). + *

A couple of tests are done in visit(ASTCompositeReference node, ... + * too. + */ + static protected ESValue acceptNull(Object v) { + if (v == null) { + // Accept null (could generate an optional exception). + return ESUndefined.theUndefined; + } else { + // Take advantage to convert... + return (ESValue) v; + } + } } - - diff --git a/src/FESI/Interpreter/FesiHashtable.java b/src/FESI/Interpreter/FesiHashtable.java index b8051ce5..75507c20 100644 --- a/src/FESI/Interpreter/FesiHashtable.java +++ b/src/FESI/Interpreter/FesiHashtable.java @@ -349,7 +349,7 @@ class FesiHashtable implements Cloneable { public ESValue put(String key, int hash, boolean hidden, boolean readonly, ESValue value) { // Make sure the value is not null if (value == null) { - throw new NullPointerException(); + throw new NullPointerException("value"); } // Makes sure the key is not already in the hashtable. diff --git a/src/FESI/Parser/EcmaScript.java b/src/FESI/Parser/EcmaScript.java index 1466b10f..7e73eff3 100644 --- a/src/FESI/Parser/EcmaScript.java +++ b/src/FESI/Parser/EcmaScript.java @@ -3164,14 +3164,6 @@ public class EcmaScript/*@bgen(jjtree)*/implements EcmaScriptTreeConstants, Ecma return false; } - final private boolean jj_3R_60() { - if (jj_3R_64()) return true; - if (jj_la == 0 && jj_scanpos == jj_lastpos) return false; - if (jj_3R_59()) return true; - if (jj_la == 0 && jj_scanpos == jj_lastpos) return false; - return false; - } - final private boolean jj_3R_24() { if (jj_scan_token(FOR)) return true; if (jj_la == 0 && jj_scanpos == jj_lastpos) return false; @@ -3182,6 +3174,14 @@ public class EcmaScript/*@bgen(jjtree)*/implements EcmaScriptTreeConstants, Ecma return false; } + final private boolean jj_3R_60() { + if (jj_3R_64()) return true; + if (jj_la == 0 && jj_scanpos == jj_lastpos) return false; + if (jj_3R_59()) return true; + if (jj_la == 0 && jj_scanpos == jj_lastpos) return false; + return false; + } + final private boolean jj_3R_131() { if (jj_3R_138()) return true; if (jj_la == 0 && jj_scanpos == jj_lastpos) return false; diff --git a/src/FESI/Parser/EcmaScriptTokenManager.java b/src/FESI/Parser/EcmaScriptTokenManager.java index 3b6d7506..43ef1663 100644 --- a/src/FESI/Parser/EcmaScriptTokenManager.java +++ b/src/FESI/Parser/EcmaScriptTokenManager.java @@ -1654,6 +1654,13 @@ final void SkipLexicalActions(Token matchedToken) { switch(jjmatchedKind) { + case 8 : + if (image == null) + image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); + else + image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); + input_stream.backup(1); + break; default : break; }