зеркало из https://github.com/mozilla/pjs.git
Making invalid left hand of assignment runtime reference error instead of syntax error as dictated by ECMAScript. Now interpreter/class compiler generates code that calls ScriptRuntime.genericReference() that in turn throws the error.
This commit is contained in:
Родитель
2361dfc4fe
Коммит
ef83ead18b
|
@ -838,17 +838,20 @@ class IRFactory
|
|||
n.putIntProp(Node.INCRDECR_PROP, incrDecrMask);
|
||||
return n;
|
||||
}
|
||||
case Token.CALL: {
|
||||
// Turn call into reference_call and recurse
|
||||
child.setType(Token.REF_CALL);
|
||||
Node ref = new Node(Token.GET_REF, child);
|
||||
return createIncDec(nodeType, post, ref);
|
||||
}
|
||||
}
|
||||
// TODO: This should be a ReferenceError--but that's a runtime
|
||||
// exception. Should we compile an exception into the code?
|
||||
parser.reportError("msg.bad.lhs.assign");
|
||||
return child;
|
||||
return createIncDec(nodeType, post, makeReferenceGet(child));
|
||||
}
|
||||
|
||||
private Node makeReferenceGet(Node node)
|
||||
{
|
||||
Node ref;
|
||||
if (node.getType() == Token.CALL) {
|
||||
node.setType(Token.REF_CALL);
|
||||
ref = node;
|
||||
} else {
|
||||
ref = new Node(Token.GENERIC_REF, node);
|
||||
}
|
||||
return new Node(Token.GET_REF, ref);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1054,17 +1057,8 @@ class IRFactory
|
|||
Node ref = left.getFirstChild();
|
||||
return new Node(Token.SET_REF, ref, right);
|
||||
}
|
||||
case Token.CALL: {
|
||||
left.setType(Token.REF_CALL);
|
||||
return new Node(Token.SET_REF, left, right);
|
||||
}
|
||||
|
||||
default:
|
||||
// TODO: This should be a ReferenceError--but that's a runtime
|
||||
// exception. Should we compile an exception into the code?
|
||||
parser.reportError("msg.bad.lhs.assign");
|
||||
return left;
|
||||
}
|
||||
return createAssignment(makeReferenceGet(left), right);
|
||||
}
|
||||
|
||||
Object createAssignmentOp(int assignOp, Object leftObj, Object rightObj)
|
||||
|
@ -1082,7 +1076,6 @@ class IRFactory
|
|||
Node lvalueLeft = Node.newString(Token.BINDNAME, s);
|
||||
return new Node(Token.SETNAME, lvalueLeft, op);
|
||||
}
|
||||
|
||||
case Token.GETPROP:
|
||||
case Token.GETELEM: {
|
||||
Node obj = left.getFirstChild();
|
||||
|
@ -1096,26 +1089,14 @@ class IRFactory
|
|||
Node op = new Node(assignOp, opLeft, right);
|
||||
return new Node(type, obj, id, op);
|
||||
}
|
||||
|
||||
case Token.GET_REF: {
|
||||
Node ref = left.getFirstChild();
|
||||
Node opLeft = new Node(Token.USE_STACK);
|
||||
Node op = new Node(assignOp, opLeft, right);
|
||||
return new Node(Token.SET_REF_OP, ref, op);
|
||||
}
|
||||
case Token.CALL: {
|
||||
// Turn call into reference_call and recurse
|
||||
left.setType(Token.REF_CALL);
|
||||
Node ref = new Node(Token.GET_REF, left);
|
||||
return createAssignmentOp(assignOp, ref, right);
|
||||
}
|
||||
|
||||
default:
|
||||
// TODO: This should be a ReferenceError--but that's a runtime
|
||||
// exception. Should we compile an exception into the code?
|
||||
parser.reportError("msg.bad.lhs.assign");
|
||||
return left;
|
||||
}
|
||||
return createAssignmentOp(assignOp, makeReferenceGet(left), right);
|
||||
}
|
||||
|
||||
Node createUseLocal(Node localBlock)
|
||||
|
|
|
@ -129,11 +129,8 @@ public class Interpreter
|
|||
Icode_GETVAR1 = -43,
|
||||
Icode_SETVAR1 = -44,
|
||||
|
||||
// Construct special reference
|
||||
Icode_SPECIAL_REF = -45,
|
||||
|
||||
// Last icode
|
||||
MIN_ICODE = -45;
|
||||
MIN_ICODE = -44;
|
||||
|
||||
static {
|
||||
// Checks for byte code consistencies, good compiler can eliminate them
|
||||
|
@ -1051,11 +1048,17 @@ public class Interpreter
|
|||
stackDelta = 1;
|
||||
iCodeTop = generateICode(child, iCodeTop);
|
||||
int special = node.getExistingIntProp(Node.SPECIAL_PROP_PROP);
|
||||
iCodeTop = addIcode(Icode_SPECIAL_REF, iCodeTop);
|
||||
iCodeTop = addToken(Token.SPECIAL_REF, iCodeTop);
|
||||
iCodeTop = addByte(special, iCodeTop);
|
||||
break;
|
||||
}
|
||||
|
||||
case Token.GENERIC_REF:
|
||||
stackDelta = 1;
|
||||
iCodeTop = generateICode(child, iCodeTop);
|
||||
iCodeTop = addToken(Token.GENERIC_REF, iCodeTop);
|
||||
break;
|
||||
|
||||
default :
|
||||
throw badTree(node);
|
||||
}
|
||||
|
@ -1638,7 +1641,6 @@ public class Interpreter
|
|||
case Icode_REG_STR4: return "LOAD_STR4";
|
||||
case Icode_GETVAR1: return "GETVAR1";
|
||||
case Icode_SETVAR1: return "SETVAR1";
|
||||
case Icode_SPECIAL_REF: return "SPECIAL_REF";
|
||||
}
|
||||
|
||||
// icode without name
|
||||
|
@ -1695,7 +1697,7 @@ public class Interpreter
|
|||
break;
|
||||
}
|
||||
|
||||
case Icode_SPECIAL_REF : {
|
||||
case Token.SPECIAL_REF : {
|
||||
int specialType = iCode[pc];
|
||||
out.println(tname + " " + specialType);
|
||||
++pc;
|
||||
|
@ -1861,7 +1863,7 @@ public class Interpreter
|
|||
// type of ++/--
|
||||
return 1 + 1;
|
||||
|
||||
case Icode_SPECIAL_REF:
|
||||
case Token.SPECIAL_REF:
|
||||
// type of special property
|
||||
return 1 + 1;
|
||||
|
||||
|
@ -2828,13 +2830,20 @@ switch (op) {
|
|||
stack[++stackTop] = ScriptRuntime.getParent(lhs);
|
||||
continue Loop;
|
||||
}
|
||||
case Icode_SPECIAL_REF : {
|
||||
case Token.SPECIAL_REF : {
|
||||
Object lhs = stack[stackTop];
|
||||
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
|
||||
stack[stackTop] = ScriptRuntime.specialReference(lhs, scope, iCode[pc]);
|
||||
stack[stackTop] = ScriptRuntime.specialReference(lhs, iCode[pc],
|
||||
cx, scope);
|
||||
++pc;
|
||||
continue Loop;
|
||||
}
|
||||
case Token.GENERIC_REF : {
|
||||
Object lhs = stack[stackTop];
|
||||
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
|
||||
stack[stackTop] = ScriptRuntime.genericReference(lhs, cx, scope);
|
||||
continue Loop;
|
||||
}
|
||||
case Icode_SCOPE :
|
||||
stack[++stackTop] = scope;
|
||||
continue Loop;
|
||||
|
|
|
@ -1277,8 +1277,9 @@ public class ScriptRuntime {
|
|||
}
|
||||
|
||||
public static Object specialReference(final Object obj,
|
||||
final Scriptable scope,
|
||||
final int specialType)
|
||||
final int specialType,
|
||||
Context cx,
|
||||
final Scriptable scope)
|
||||
{
|
||||
if (!(specialType == Node.SPECIAL_PROP_PROTO
|
||||
|| specialType == Node.SPECIAL_PROP_PARENT))
|
||||
|
@ -1306,6 +1307,13 @@ public class ScriptRuntime {
|
|||
};
|
||||
}
|
||||
|
||||
public static Object genericReference(Object obj,
|
||||
Context cx, Scriptable scope)
|
||||
{
|
||||
String msg = getMessage1("msg.not.ref", toString(obj));
|
||||
throw constructError("ReferenceError", msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* The delete operator
|
||||
*
|
||||
|
|
|
@ -143,71 +143,72 @@ public class Token
|
|||
GET_REF = 69, // *reference
|
||||
SET_REF = 70, // *reference = something
|
||||
REF_CALL = 71, // f(args) = something or f(args)++
|
||||
SPECIAL_REF = 72, // reference for special properties like __proto
|
||||
GENERIC_REF = 73, // generic reference to generate runtime ref errors
|
||||
|
||||
LAST_BYTECODE_TOKEN = 71,
|
||||
LAST_BYTECODE_TOKEN = 73,
|
||||
// End of interpreter bytecodes
|
||||
|
||||
TRY = 72,
|
||||
SEMI = 73, // semicolon
|
||||
LB = 74, // left and right brackets
|
||||
RB = 75,
|
||||
LC = 76, // left and right curlies (braces)
|
||||
RC = 77,
|
||||
LP = 78, // left and right parentheses
|
||||
RP = 79,
|
||||
COMMA = 80, // comma operator
|
||||
ASSIGN = 81, // simple assignment (=)
|
||||
ASSIGNOP = 82, // assignment with operation (+= -= etc.)
|
||||
HOOK = 83, // conditional (?:)
|
||||
COLON = 84,
|
||||
OR = 85, // logical or (||)
|
||||
AND = 86, // logical and (&&)
|
||||
INC = 87, // increment/decrement (++ --)
|
||||
DEC = 88,
|
||||
DOT = 89, // member operator (.)
|
||||
FUNCTION = 90, // function keyword
|
||||
EXPORT = 91, // export keyword
|
||||
IMPORT = 92, // import keyword
|
||||
IF = 93, // if keyword
|
||||
ELSE = 94, // else keyword
|
||||
SWITCH = 95, // switch keyword
|
||||
CASE = 96, // case keyword
|
||||
DEFAULT = 97, // default keyword
|
||||
WHILE = 98, // while keyword
|
||||
DO = 99, // do keyword
|
||||
FOR = 100, // for keyword
|
||||
BREAK = 101, // break keyword
|
||||
CONTINUE = 102, // continue keyword
|
||||
VAR = 103, // var keyword
|
||||
WITH = 104, // with keyword
|
||||
CATCH = 105, // catch keyword
|
||||
FINALLY = 106, // finally keyword
|
||||
VOID = 107, // void keyword
|
||||
RESERVED = 108, // reserved keywords
|
||||
TRY = 74,
|
||||
SEMI = 75, // semicolon
|
||||
LB = 76, // left and right brackets
|
||||
RB = 77,
|
||||
LC = 78, // left and right curlies (braces)
|
||||
RC = 79,
|
||||
LP = 80, // left and right parentheses
|
||||
RP = 81,
|
||||
COMMA = 82, // comma operator
|
||||
ASSIGN = 83, // simple assignment (=)
|
||||
ASSIGNOP = 84, // assignment with operation (+= -= etc.)
|
||||
HOOK = 85, // conditional (?:)
|
||||
COLON = 86,
|
||||
OR = 87, // logical or (||)
|
||||
AND = 88, // logical and (&&)
|
||||
INC = 89, // increment/decrement (++ --)
|
||||
DEC = 90,
|
||||
DOT = 91, // member operator (.)
|
||||
FUNCTION = 92, // function keyword
|
||||
EXPORT = 93, // export keyword
|
||||
IMPORT = 94, // import keyword
|
||||
IF = 95, // if keyword
|
||||
ELSE = 96, // else keyword
|
||||
SWITCH = 97, // switch keyword
|
||||
CASE = 98, // case keyword
|
||||
DEFAULT = 99, // default keyword
|
||||
WHILE = 100, // while keyword
|
||||
DO = 101, // do keyword
|
||||
FOR = 102, // for keyword
|
||||
BREAK = 103, // break keyword
|
||||
CONTINUE = 104, // continue keyword
|
||||
VAR = 105, // var keyword
|
||||
WITH = 106, // with keyword
|
||||
CATCH = 107, // catch keyword
|
||||
FINALLY = 108, // finally keyword
|
||||
VOID = 109, // void keyword
|
||||
RESERVED = 110, // reserved keywords
|
||||
|
||||
EMPTY = 109,
|
||||
EMPTY = 111,
|
||||
|
||||
/* types used for the parse tree - these never get returned
|
||||
* by the scanner.
|
||||
*/
|
||||
|
||||
BLOCK = 110, // statement block
|
||||
LABEL = 111, // label
|
||||
TARGET = 112,
|
||||
LOOP = 113,
|
||||
EXPRSTMT = 114,
|
||||
JSR = 115,
|
||||
SCRIPT = 116, // top-level node for entire script
|
||||
TYPEOFNAME = 117, // for typeof(simple-name)
|
||||
USE_STACK = 118,
|
||||
SETPROP_OP = 119, // x.y op= something
|
||||
SETELEM_OP = 120, // x[y] op= something
|
||||
INIT_LIST = 121,
|
||||
LOCAL_BLOCK = 122,
|
||||
SET_REF_OP = 123, // *reference op= something
|
||||
SPECIAL_REF = 124, // reference for special properties like __proto
|
||||
BLOCK = 112, // statement block
|
||||
LABEL = 113, // label
|
||||
TARGET = 114,
|
||||
LOOP = 115,
|
||||
EXPRSTMT = 116,
|
||||
JSR = 117,
|
||||
SCRIPT = 118, // top-level node for entire script
|
||||
TYPEOFNAME = 119, // for typeof(simple-name)
|
||||
USE_STACK = 120,
|
||||
SETPROP_OP = 121, // x.y op= something
|
||||
SETELEM_OP = 122, // x[y] op= something
|
||||
INIT_LIST = 123,
|
||||
LOCAL_BLOCK = 124,
|
||||
SET_REF_OP = 125, // *reference op= something
|
||||
|
||||
LAST_TOKEN = 124;
|
||||
LAST_TOKEN = 125;
|
||||
|
||||
public static String name(int token)
|
||||
{
|
||||
|
@ -293,6 +294,8 @@ public class Token
|
|||
case GET_REF: return "GET_REF";
|
||||
case SET_REF: return "SET_REF";
|
||||
case REF_CALL: return "REF_CALL";
|
||||
case SPECIAL_REF: return "SPECIAL_REF";
|
||||
case GENERIC_REF: return "GENERIC_REF";
|
||||
case TRY: return "TRY";
|
||||
case SEMI: return "SEMI";
|
||||
case LB: return "LB";
|
||||
|
@ -344,7 +347,6 @@ public class Token
|
|||
case INIT_LIST: return "INIT_LIST";
|
||||
case LOCAL_BLOCK: return "LOCAL_BLOCK";
|
||||
case SET_REF_OP: return "SET_REF_OP";
|
||||
case SPECIAL_REF: return "SPECIAL_REF";
|
||||
}
|
||||
|
||||
// Token without name
|
||||
|
|
|
@ -1850,6 +1850,10 @@ class BodyCodegen
|
|||
visitSpecialRef(node, child);
|
||||
break;
|
||||
|
||||
case Token.GENERIC_REF:
|
||||
visitGenericRef(node, child);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Unexpected node type "+type);
|
||||
}
|
||||
|
@ -3508,12 +3512,26 @@ class BodyCodegen
|
|||
{
|
||||
int special = node.getExistingIntProp(Node.SPECIAL_PROP_PROP);
|
||||
generateCodeFromNode(child, node);
|
||||
cfw.addALoad(variableObjectLocal); // get variable object
|
||||
cfw.addPush(special); // push name
|
||||
cfw.addPush(special);
|
||||
cfw.addALoad(contextLocal);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
addScriptRuntimeInvoke("specialReference",
|
||||
"(Ljava/lang/Object;"
|
||||
"(Ljava/lang/Object;I"
|
||||
+"Lorg/mozilla/javascript/Context;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+"I)Ljava/lang/Object;");
|
||||
+")Ljava/lang/Object;");
|
||||
}
|
||||
|
||||
private void visitGenericRef(Node node, Node child)
|
||||
{
|
||||
generateCodeFromNode(child, node);
|
||||
cfw.addALoad(contextLocal);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
addScriptRuntimeInvoke("genericReference",
|
||||
"(Ljava/lang/Object;"
|
||||
+"Lorg/mozilla/javascript/Context;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Ljava/lang/Object;");
|
||||
}
|
||||
|
||||
private int getLocalBlockRegister(Node node)
|
||||
|
|
|
@ -102,9 +102,6 @@ msg.method.not.found =\
|
|||
msg.bad.for.in.lhs =\
|
||||
Invalid left-hand side of for..in loop.
|
||||
|
||||
msg.bad.lhs.assign =\
|
||||
Invalid assignment left-hand side.
|
||||
|
||||
msg.mult.index =\
|
||||
Only one variable allowed in for..in loop.
|
||||
|
||||
|
@ -417,6 +414,10 @@ msg.no.ref.from.function =\
|
|||
Function {0} can not be used as the left-hand side of assignment \
|
||||
or as an operand of ++ or -- operator.
|
||||
|
||||
msg.not.ref =\
|
||||
{0} can not be used as the left-hand side of assignment \
|
||||
or as an operand of ++ or -- operator.
|
||||
|
||||
msg.bad.default.value =\
|
||||
Object''s getDefaultValue() method returned an object.
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче