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:
igor%mir2.org 2004-05-31 15:49:19 +00:00
Родитель 2361dfc4fe
Коммит ef83ead18b
6 изменённых файлов: 128 добавлений и 109 удалений

Просмотреть файл

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