Merged in changes from FESI 1.1.5
This commit is contained in:
parent
19fd7b0f7d
commit
719959353e
5 changed files with 95 additions and 55 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue