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
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue