Merged in changes from FESI 1.1.5

This commit is contained in:
hns 2002-11-29 17:56:44 +00:00
parent 19fd7b0f7d
commit 719959353e
5 changed files with 95 additions and 55 deletions

View file

@ -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; i<argumentValues.length; i++) {
for (int i=0; i<maxArgs; i++) {
ESValue val = (i<argumentValues.length) ? argumentValues[i] :
ESUndefined.theUndefined;
if (i<argumentNames.length) {

View file

@ -247,14 +247,14 @@ public class EcmaScriptEvaluateVisitor
boolean b2 =v2.booleanValue();
return b1==b2;
}
// ESNode wrappers must be checked with equals() because
// it's possible that different wrappers wrap the same node!
if (v1 instanceof helma.scripting.fesi.ESNode ||
v1 instanceof helma.scripting.fesi.ESGenericObject) {
if (v1 instanceof helma.scripting.fesi.ESNode ||
v1 instanceof helma.scripting.fesi.ESGenericObject) {
return v1.equals (v2);
}
return v1 == v2;
}
@ -311,8 +311,8 @@ public class EcmaScriptEvaluateVisitor
public Object visit(ASTStatementList node, Object data) {
int n = node.jjtGetNumChildren();
// Accepts empty statement lists (for example generated
// by function(){}
// Return ESUndefined for empty statement lists (for
// example generated by calling 'function(){}')
Object result = ESUndefined.theUndefined;
for (int i = 0; i < node.jjtGetNumChildren(); i++) {
if (completionCode != C_NORMAL) return result;
@ -344,11 +344,11 @@ public class EcmaScriptEvaluateVisitor
}
public Object visit(ASTVariableDeclaration node, Object data) {
Object result = null;
int nChildren = node.jjtGetNumChildren();
if (nChildren<1 || nChildren>2) {
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() && (i<nChildren)) {
result = (ESValue) node.jjtGetChild(i).jjtAccept(this,FOR_VALUE);
result = acceptNull(node.jjtGetChild(i).jjtAccept(this,FOR_VALUE));
i ++;
}
// Normalize to primitive - could be optimized...
@ -1186,10 +1194,10 @@ public class EcmaScriptEvaluateVisitor
int nChildren = node.jjtGetNumChildren();
ESValue result = null;
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()) && (i<nChildren)) {
result = (ESValue) node.jjtGetChild(i).jjtAccept(this,FOR_VALUE);
result = acceptNull(node.jjtGetChild(i).jjtAccept(this,FOR_VALUE));
i ++;
}
// Normalize to primitive - could be optimized...
@ -1210,7 +1218,7 @@ public class EcmaScriptEvaluateVisitor
node.assertThreeChildren();
Object result = null;
try {
ESValue t = (ESValue) node.jjtGetChild(0).jjtAccept(this,FOR_VALUE);
ESValue t = acceptNull(node.jjtGetChild(0).jjtAccept(this,FOR_VALUE));
boolean test = t.booleanValue();
if (test) {
result = node.jjtGetChild(1).jjtAccept(this, FOR_VALUE);
@ -1228,7 +1236,6 @@ public class EcmaScriptEvaluateVisitor
ESValue result = null;
try {
// Get left hand side
Object lvo = node.jjtGetChild(0).jjtAccept(this,FOR_REFERENCE);
//System.out.println("REF: " + lvo);
ESReference lv;
@ -1238,8 +1245,7 @@ public class EcmaScriptEvaluateVisitor
throw new EcmaScriptException("Value '"+lvo.toString()+"' is not an assignable object or property");
}
// get Right hand side
ESValue v2 = (ESValue) node.jjtGetChild(2).jjtAccept(this,FOR_VALUE);
ESValue v2 = acceptNull(node.jjtGetChild(2).jjtAccept(this,FOR_VALUE));
// Case analysis based on assignement operator type
int operator = ((ASTOperator)(node.jjtGetChild(1))).getOperator();
@ -1248,7 +1254,7 @@ public class EcmaScriptEvaluateVisitor
evaluator.putValue(lv, v2);
result = v2;
} else {
// All composite assignement requires a current value
// All composite assignement requires a current value
ESValue v1 = lv.getValue();
switch (operator) {
case PLUSASSIGN: {
@ -1361,7 +1367,30 @@ public class EcmaScriptEvaluateVisitor
}
return result;
}
/**
* To transform a null (empty) result (but not an ESNull!)
* in 'ESUndefined'. null results may be returned if a
* statement as the empty statement, missing else clause of
* an if statement, loop not executed at all, etc.. is executed
* for value (for example as the last statement of a called function
* used in an assignement). This is a programming error, and it
* may be useful to modify this function to generate an exception
* during debugging. However other implementation seem to accept
* ESUndefined in these cases. The standard is not totally clear
* to me.
* <P>An alternative would be to return ESUndefined in all cases,
* but then we lose a useful distinction (at least for debugging...).
* <P>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;
}
}
}

View file

@ -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.

View file

@ -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;

View file

@ -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;
}