зеркало из https://github.com/mozilla/gecko-dev.git
Fixed result value of for..in statement. Handling of user throws & runtime
errors combined. Various reader->pos bugs. Added Error & NativeError types. Added escape & unescape. Fixed bugs in Array.sort & Date settors.
This commit is contained in:
Родитель
a88a53aec1
Коммит
033e700dd8
|
@ -331,6 +331,7 @@ ByteCodeData gByteCodeData[OpCodeCount] = {
|
||||||
{ -128, "DupInsertN", },
|
{ -128, "DupInsertN", },
|
||||||
{ -1, "Pop", },
|
{ -1, "Pop", },
|
||||||
{ -128, "PopN", },
|
{ -128, "PopN", },
|
||||||
|
{ -1, "VoidPop", },
|
||||||
{ 0, "GetField", },
|
{ 0, "GetField", },
|
||||||
{ -1, "SetField", },
|
{ -1, "SetField", },
|
||||||
{ 1, "GetMethod", },
|
{ 1, "GetMethod", },
|
||||||
|
@ -729,7 +730,8 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3
|
||||||
VariableBinding *v = vs->bindings;
|
VariableBinding *v = vs->bindings;
|
||||||
bool isStatic = (vs->attributeValue->mTrueFlags & Property::Static) == Property::Static;
|
bool isStatic = (vs->attributeValue->mTrueFlags & Property::Static) == Property::Static;
|
||||||
while (v) {
|
while (v) {
|
||||||
Reference *ref = mScopeChain->getName(*v->name, vs->attributeValue->mNamespaceList, Write);
|
Reference *ref = v->scope->genReference(false, *v->name, vs->attributeValue->mNamespaceList, Write, 0);
|
||||||
|
// Reference *ref = mScopeChain->getName(*v->name, vs->attributeValue->mNamespaceList, Write);
|
||||||
ASSERT(ref); // must have been added previously by collectNames
|
ASSERT(ref); // must have been added previously by collectNames
|
||||||
if (v->initializer) {
|
if (v->initializer) {
|
||||||
if (isStatic && (static_cg != NULL)) {
|
if (isStatic && (static_cg != NULL)) {
|
||||||
|
@ -903,7 +905,7 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3
|
||||||
NOT_REACHED("what else??");
|
NOT_REACHED("what else??");
|
||||||
}
|
}
|
||||||
if (value == NULL)
|
if (value == NULL)
|
||||||
m_cx->reportError(Exception::referenceError, "Invalid for..in target");
|
m_cx->reportError(Exception::referenceError, "Invalid for..in target", p->pos);
|
||||||
iteratorReadRef->emitCodeSequence(this);
|
iteratorReadRef->emitCodeSequence(this);
|
||||||
addOp(GetPropertyOp);
|
addOp(GetPropertyOp);
|
||||||
addStringRef(m_cx->Value_StringAtom);
|
addStringRef(m_cx->Value_StringAtom);
|
||||||
|
@ -925,7 +927,7 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3
|
||||||
addLong(1);
|
addLong(1);
|
||||||
addByte(Explicit);
|
addByte(Explicit);
|
||||||
iteratorWriteRef->emitCodeSequence(this);
|
iteratorWriteRef->emitCodeSequence(this);
|
||||||
addOp(PopOp);
|
addOp(VoidPopOp);
|
||||||
|
|
||||||
setLabel(labelAtTestCondition);
|
setLabel(labelAtTestCondition);
|
||||||
iteratorReadRef->emitCodeSequence(this);
|
iteratorReadRef->emitCodeSequence(this);
|
||||||
|
@ -948,16 +950,7 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3
|
||||||
addOp(PopOp);
|
addOp(PopOp);
|
||||||
|
|
||||||
setLabel(labelAtEnd);
|
setLabel(labelAtEnd);
|
||||||
/*
|
|
||||||
if (valueBaseDepth) {
|
|
||||||
if (valueBaseDepth > 1) {
|
|
||||||
addOpAdjustDepth(PopNOp, -valueBaseDepth);
|
|
||||||
addShort(valueBaseDepth);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
addOp(PopOp);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
delete objectReadRef;
|
delete objectReadRef;
|
||||||
delete objectWriteRef;
|
delete objectWriteRef;
|
||||||
delete iteratorReadRef;
|
delete iteratorReadRef;
|
||||||
|
@ -2366,6 +2359,9 @@ BinaryOpEquals:
|
||||||
return Object_Type;
|
return Object_Type;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ExprNode::regExp:
|
||||||
|
m_cx->reportError(Exception::internalError, "Regular expressions nyi", p->pos);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
NOT_REACHED("Not Implemented Yet");
|
NOT_REACHED("Not Implemented Yet");
|
||||||
}
|
}
|
||||||
|
@ -2409,6 +2405,7 @@ uint32 printInstruction(Formatter &f, uint32 i, const ByteCodeModule& bcm)
|
||||||
case DupOp:
|
case DupOp:
|
||||||
case DupInsertOp:
|
case DupInsertOp:
|
||||||
case PopOp:
|
case PopOp:
|
||||||
|
case VoidPopOp:
|
||||||
case LoadGlobalObjectOp:
|
case LoadGlobalObjectOp:
|
||||||
case NewClosureOp:
|
case NewClosureOp:
|
||||||
case ClassOp:
|
case ClassOp:
|
||||||
|
|
|
@ -121,6 +121,7 @@ typedef enum {
|
||||||
DupInsertNOp, // <N> <N things> <object2> --> <object2> <N things> <object2>
|
DupInsertNOp, // <N> <N things> <object2> --> <object2> <N things> <object2>
|
||||||
PopOp, // <object> -->
|
PopOp, // <object> -->
|
||||||
PopNOp, // <N> <N things> -->
|
PopNOp, // <N> <N things> -->
|
||||||
|
VoidPopOp, // <object>--> (doesn't cache result value)
|
||||||
// for instance members
|
// for instance members
|
||||||
GetFieldOp, // <slot> <base> --> <object>
|
GetFieldOp, // <slot> <base> --> <object>
|
||||||
SetFieldOp, // <slot> <base> <object> --> <object>
|
SetFieldOp, // <slot> <base> <object> --> <object>
|
||||||
|
|
|
@ -51,6 +51,7 @@ static const char *const kindStrings[] = {
|
||||||
"Type error", // Yype error
|
"Type error", // Yype error
|
||||||
"Uncaught exception error", // uncaught exception error
|
"Uncaught exception error", // uncaught exception error
|
||||||
"Semantic error", // semantic error
|
"Semantic error", // semantic error
|
||||||
|
"User exception", // 'throw' from user code
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return a null-terminated string describing the exception's kind.
|
// Return a null-terminated string describing the exception's kind.
|
||||||
|
|
|
@ -55,7 +55,8 @@ namespace JavaScript
|
||||||
rangeError,
|
rangeError,
|
||||||
typeError,
|
typeError,
|
||||||
uncaughtError,
|
uncaughtError,
|
||||||
semanticError
|
semanticError,
|
||||||
|
userException
|
||||||
};
|
};
|
||||||
|
|
||||||
Kind kind; // The exception's kind
|
Kind kind; // The exception's kind
|
||||||
|
|
|
@ -63,12 +63,6 @@ namespace JavaScript {
|
||||||
namespace JS2Runtime {
|
namespace JS2Runtime {
|
||||||
|
|
||||||
|
|
||||||
class JSException {
|
|
||||||
public:
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
inline char narrow(char16 ch) { return char(ch); }
|
inline char narrow(char16 ch) { return char(ch); }
|
||||||
|
|
||||||
JSValue Context::readEvalString(const String &str, const String& fileName, ScopeChain *scopeChain, const JSValue& thisValue)
|
JSValue Context::readEvalString(const String &str, const String& fileName, ScopeChain *scopeChain, const JSValue& thisValue)
|
||||||
|
@ -78,24 +72,24 @@ JSValue Context::readEvalString(const String &str, const String& fileName, Scope
|
||||||
Arena a;
|
Arena a;
|
||||||
Parser p(mWorld, a, mFlags, str, fileName);
|
Parser p(mWorld, a, mFlags, str, fileName);
|
||||||
Reader *oldReader = mReader;
|
Reader *oldReader = mReader;
|
||||||
mReader = &p.lexer.reader;
|
setReader(&p.lexer.reader);
|
||||||
StmtNode *parsedStatements = p.parseProgram();
|
|
||||||
ASSERT(p.lexer.peek(true).hasKind(Token::end));
|
|
||||||
if (mDebugFlag)
|
|
||||||
{
|
|
||||||
PrettyPrinter f(stdOut, 30);
|
|
||||||
{
|
|
||||||
PrettyPrinter::Block b(f, 2);
|
|
||||||
f << "Program =";
|
|
||||||
f.linearBreak(1);
|
|
||||||
StmtNode::printStatements(f, parsedStatements);
|
|
||||||
}
|
|
||||||
f.end();
|
|
||||||
stdOut << '\n';
|
|
||||||
}
|
|
||||||
buildRuntime(parsedStatements);
|
|
||||||
JS2Runtime::ByteCodeModule* bcm = genCode(parsedStatements, fileName);
|
|
||||||
try {
|
try {
|
||||||
|
StmtNode *parsedStatements = p.parseProgram();
|
||||||
|
ASSERT(p.lexer.peek(true).hasKind(Token::end));
|
||||||
|
if (mDebugFlag)
|
||||||
|
{
|
||||||
|
PrettyPrinter f(stdOut, 30);
|
||||||
|
{
|
||||||
|
PrettyPrinter::Block b(f, 2);
|
||||||
|
f << "Program =";
|
||||||
|
f.linearBreak(1);
|
||||||
|
StmtNode::printStatements(f, parsedStatements);
|
||||||
|
}
|
||||||
|
f.end();
|
||||||
|
stdOut << '\n';
|
||||||
|
}
|
||||||
|
buildRuntime(parsedStatements);
|
||||||
|
JS2Runtime::ByteCodeModule* bcm = genCode(parsedStatements, fileName);
|
||||||
if (bcm) {
|
if (bcm) {
|
||||||
setReader(NULL);
|
setReader(NULL);
|
||||||
bcm->setSource(str, fileName);
|
bcm->setSource(str, fileName);
|
||||||
|
@ -103,10 +97,11 @@ JSValue Context::readEvalString(const String &str, const String& fileName, Scope
|
||||||
delete bcm;
|
delete bcm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (JSException *x) {
|
catch (Exception &x) {
|
||||||
setReader(oldReader);
|
setReader(oldReader);
|
||||||
throw x;
|
throw x;
|
||||||
}
|
}
|
||||||
|
setReader(oldReader);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,7 +215,7 @@ JSValue Context::interpret(JS2Runtime::ByteCodeModule *bcm, int offset, ScopeCha
|
||||||
try {
|
try {
|
||||||
result = interpret(pc, endPC);
|
result = interpret(pc, endPC);
|
||||||
}
|
}
|
||||||
catch (JSException *x) {
|
catch (Exception &x) {
|
||||||
Activation *prev = mActivationStack.top();
|
Activation *prev = mActivationStack.top();
|
||||||
mActivationStack.pop();
|
mActivationStack.pop();
|
||||||
|
|
||||||
|
@ -420,7 +415,12 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
||||||
switch ((ByteCodeOp)(*pc++)) {
|
switch ((ByteCodeOp)(*pc++)) {
|
||||||
case PopOp:
|
case PopOp:
|
||||||
{
|
{
|
||||||
result = popValue(); // XXX debug only? - just decrement top
|
result = popValue();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VoidPopOp:
|
||||||
|
{
|
||||||
|
popValue(); // XXX just decrement top
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PopNOp:
|
case PopNOp:
|
||||||
|
@ -627,22 +627,18 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
||||||
if (target->isPrototype() && mThis.isNull())
|
if (target->isPrototype() && mThis.isNull())
|
||||||
mThis = JSValue(getGlobalObject());
|
mThis = JSValue(getGlobalObject());
|
||||||
|
|
||||||
JSValue *argBase = getBase(stackSize() - argCount);
|
|
||||||
|
|
||||||
if (!target->isNative()) {
|
if (!target->isNative()) {
|
||||||
|
JSValue *argBase = buildArgumentBlock(target, argCount);
|
||||||
// XXX Optimize the more typical case in which there are no named arguments, no optional arguments
|
// XXX Optimize the more typical case in which there are no named arguments, no optional arguments
|
||||||
// and the appropriate number of arguments have been supplied.
|
// and the appropriate number of arguments have been supplied.
|
||||||
|
|
||||||
argBase = buildArgumentBlock(target, argCount);
|
|
||||||
|
|
||||||
mActivationStack.push(new Activation(mLocals, mStack, mStackTop - (cleanUp + 1),
|
mActivationStack.push(new Activation(mLocals, mStack, mStackTop - (cleanUp + 1),
|
||||||
mScopeChain,
|
mScopeChain,
|
||||||
mArgumentBase, oldThis,
|
mArgumentBase, oldThis,
|
||||||
pc, mCurModule));
|
pc, mCurModule));
|
||||||
mScopeChain = target->getScopeChain();
|
mScopeChain = target->getScopeChain();
|
||||||
// if (mThis.isObject())
|
mScopeChain->addScope(target->getParameterBarrel());
|
||||||
// mScopeChain->addScope(mThis.object);
|
mScopeChain->addScope(target->getActivation());
|
||||||
|
|
||||||
if (!target->isChecked()) {
|
if (!target->isChecked()) {
|
||||||
JSArrayInstance *args = (JSArrayInstance *)Array_Type->newInstance(this);
|
JSArrayInstance *args = (JSArrayInstance *)Array_Type->newInstance(this);
|
||||||
|
@ -651,9 +647,6 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
||||||
mScopeChain->defineVariable(this, Arguments_StringAtom, NULL, Array_Type, JSValue(args));
|
mScopeChain->defineVariable(this, Arguments_StringAtom, NULL, Array_Type, JSValue(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
mScopeChain->addScope(target->getParameterBarrel());
|
|
||||||
mScopeChain->addScope(target->getActivation());
|
|
||||||
|
|
||||||
mCurModule = target->getByteCode();
|
mCurModule = target->getByteCode();
|
||||||
pc = mCurModule->mCodeBase;
|
pc = mCurModule->mCodeBase;
|
||||||
endPC = mCurModule->mCodeBase + mCurModule->mLength;
|
endPC = mCurModule->mCodeBase + mCurModule->mLength;
|
||||||
|
@ -664,6 +657,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
||||||
mStackTop = 0;
|
mStackTop = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
JSValue *argBase = getBase(stackSize() - argCount);
|
||||||
// native functions may still need access to information
|
// native functions may still need access to information
|
||||||
// about the currently executing function.
|
// about the currently executing function.
|
||||||
mActivationStack.push(new Activation(mLocals, mStack, mStackTop - (cleanUp + 1),
|
mActivationStack.push(new Activation(mLocals, mStack, mStackTop - (cleanUp + 1),
|
||||||
|
@ -790,10 +784,10 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
||||||
uint32 index = *((uint32 *)pc);
|
uint32 index = *((uint32 *)pc);
|
||||||
pc += sizeof(uint32);
|
pc += sizeof(uint32);
|
||||||
const String &name = *mCurModule->getString(index);
|
const String &name = *mCurModule->getString(index);
|
||||||
PropertyIterator it;
|
if (mScopeChain->deleteName(this, name, CURRENT_ATTR))
|
||||||
if (mScopeChain->hasOwnProperty(name, CURRENT_ATTR, Read, &it))
|
pushValue(kTrueValue);
|
||||||
mScopeChain->deleteProperty(name, CURRENT_ATTR);
|
else
|
||||||
pushValue(kTrueValue);
|
pushValue(kFalseValue);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DeleteOp:
|
case DeleteOp:
|
||||||
|
@ -907,8 +901,18 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
||||||
else
|
else
|
||||||
reportError(Exception::typeError, "InstanceOf couldn't find [[hasInstance]]");
|
reportError(Exception::typeError, "InstanceOf couldn't find [[hasInstance]]");
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
reportError(Exception::typeError, "InstanceOf needs function object");
|
// XXX hack for <= ECMA 3 compatibility
|
||||||
|
if (t.isType()) {
|
||||||
|
if ((v.getType() == t.type)
|
||||||
|
|| v.getType()->derivesFrom(t.type))
|
||||||
|
pushValue(kTrueValue);
|
||||||
|
else
|
||||||
|
pushValue(kFalseValue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
reportError(Exception::typeError, "InstanceOf needs function object");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GetNameOp:
|
case GetNameOp:
|
||||||
|
@ -994,7 +998,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
||||||
try {
|
try {
|
||||||
result = interpret(target->getByteCode(), 0, target->getScopeChain(), argBase[0], argBase, argCount);
|
result = interpret(target->getByteCode(), 0, target->getScopeChain(), argBase[0], argBase, argCount);
|
||||||
}
|
}
|
||||||
catch (JSException *x) {
|
catch (Exception &x) {
|
||||||
delete[] argBase;
|
delete[] argBase;
|
||||||
throw x;
|
throw x;
|
||||||
}
|
}
|
||||||
|
@ -1050,7 +1054,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
||||||
try {
|
try {
|
||||||
result = interpret(target->getByteCode(), 0, target->getScopeChain(), *baseValue, argBase, argCount);
|
result = interpret(target->getByteCode(), 0, target->getScopeChain(), *baseValue, argBase, argCount);
|
||||||
}
|
}
|
||||||
catch (JSException *x) {
|
catch (Exception &x) {
|
||||||
delete[] argBase;
|
delete[] argBase;
|
||||||
throw x;
|
throw x;
|
||||||
}
|
}
|
||||||
|
@ -1105,7 +1109,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
||||||
try {
|
try {
|
||||||
result = interpret(target->getByteCode(), 0, target->getScopeChain(), kNullValue, argBase, argCount);
|
result = interpret(target->getByteCode(), 0, target->getScopeChain(), kNullValue, argBase, argCount);
|
||||||
}
|
}
|
||||||
catch (JSException *x) {
|
catch (Exception &x) {
|
||||||
delete[] argBase;
|
delete[] argBase;
|
||||||
throw x;
|
throw x;
|
||||||
}
|
}
|
||||||
|
@ -1341,12 +1345,12 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
||||||
JSArrayInstance *args = (JSArrayInstance *)Array_Type->newInstance(this);
|
JSArrayInstance *args = (JSArrayInstance *)Array_Type->newInstance(this);
|
||||||
for (uint32 i = 0; i < argCount; i++)
|
for (uint32 i = 0; i < argCount; i++)
|
||||||
args->setProperty(this, *numberToString(i), NULL, argBase[i]);
|
args->setProperty(this, *numberToString(i), NULL, argBase[i]);
|
||||||
mScopeChain->defineVariable(this, Arguments_StringAtom, NULL, Array_Type, JSValue(args));
|
target->getScopeChain()->defineVariable(this, Arguments_StringAtom, NULL, Array_Type, JSValue(args));
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
result = interpret(target->getByteCode(), 0, target->getScopeChain(), newThis, argBase, argCount);
|
result = interpret(target->getByteCode(), 0, target->getScopeChain(), newThis, argBase, argCount);
|
||||||
}
|
}
|
||||||
catch (JSException *x) {
|
catch (Exception &x) {
|
||||||
delete[] argBase;
|
delete[] argBase;
|
||||||
throw x;
|
throw x;
|
||||||
}
|
}
|
||||||
|
@ -1553,41 +1557,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
||||||
break;
|
break;
|
||||||
case ThrowOp:
|
case ThrowOp:
|
||||||
{
|
{
|
||||||
throw new JSException();
|
throw Exception(Exception::userException, "");
|
||||||
/*
|
|
||||||
if (mTryStack.size() > 0) {
|
|
||||||
HandlerData *hndlr = (HandlerData *)mTryStack.top();
|
|
||||||
Activation *curAct = (mActivationStack.size() > 0) ? mActivationStack.top() : NULL;
|
|
||||||
if (curAct != hndlr->mActivation) {
|
|
||||||
ASSERT(mActivationStack.size() > 0);
|
|
||||||
Activation *prev;// = mActivationStack.top();
|
|
||||||
do {
|
|
||||||
prev = curAct;
|
|
||||||
if (prev->mPC == NULL) {
|
|
||||||
// Yikes! the exception is getting thrown across a re-invocation
|
|
||||||
// of the interpreter loop.
|
|
||||||
ASSERT(false);
|
|
||||||
}
|
|
||||||
mActivationStack.pop();
|
|
||||||
curAct = mActivationStack.top();
|
|
||||||
} while (hndlr->mActivation != curAct);
|
|
||||||
mCurModule = prev->mModule;
|
|
||||||
endPC = mCurModule->mCodeBase + mCurModule->mLength;
|
|
||||||
mLocals = prev->mLocals;
|
|
||||||
mStack = prev->mStack;
|
|
||||||
mStackTop = 1; // just the exception object remains
|
|
||||||
mStackMax = mCurModule->mStackDepth;
|
|
||||||
mArgumentBase = prev->mArgumentBase;
|
|
||||||
mThis = prev->mThis;
|
|
||||||
}
|
|
||||||
|
|
||||||
resizeStack(hndlr->mStackSize);
|
|
||||||
pc = hndlr->mPC;
|
|
||||||
pushValue(x);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
reportError(Exception::uncaughtError, "No handler for throw");
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ClassOp:
|
case ClassOp:
|
||||||
|
@ -1651,11 +1621,38 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
||||||
reportError(Exception::internalError, "Bad Opcode");
|
reportError(Exception::internalError, "Bad Opcode");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (JSException *jsx) {
|
catch (Exception &jsx) {
|
||||||
JSValue x = topValue();
|
|
||||||
if (mTryStack.size() > 0) {
|
if (mTryStack.size() > 0) {
|
||||||
HandlerData *hndlr = (HandlerData *)mTryStack.top();
|
HandlerData *hndlr = (HandlerData *)mTryStack.top();
|
||||||
Activation *curAct = (mActivationStack.size() > 0) ? mActivationStack.top() : NULL;
|
Activation *curAct = (mActivationStack.size() > 0) ? mActivationStack.top() : NULL;
|
||||||
|
|
||||||
|
JSValue x;
|
||||||
|
// make sure there's a JS object for the catch clause to work with
|
||||||
|
if (!jsx.hasKind(Exception::userException)) {
|
||||||
|
JSValue argv[1];
|
||||||
|
argv[0] = JSValue(new String(jsx.fullMessage()));
|
||||||
|
switch (jsx.kind) {
|
||||||
|
case Exception::syntaxError:
|
||||||
|
x = SyntaxError_Constructor(this, kNullValue, argv, 1);
|
||||||
|
break;
|
||||||
|
case Exception::referenceError:
|
||||||
|
x = ReferenceError_Constructor(this, kNullValue, argv, 1);
|
||||||
|
break;
|
||||||
|
case Exception::typeError:
|
||||||
|
x = TypeError_Constructor(this, kNullValue, argv, 1);
|
||||||
|
break;
|
||||||
|
case Exception::rangeError:
|
||||||
|
x = RangeError_Constructor(this, kNullValue, argv, 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
x = Error_Constructor(this, kNullValue, argv, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
x = popValue();
|
||||||
|
}
|
||||||
|
|
||||||
if (curAct != hndlr->mActivation) {
|
if (curAct != hndlr->mActivation) {
|
||||||
ASSERT(mActivationStack.size() > 0);
|
ASSERT(mActivationStack.size() > 0);
|
||||||
Activation *prev;// = mActivationStack.top();
|
Activation *prev;// = mActivationStack.top();
|
||||||
|
@ -1673,7 +1670,6 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
||||||
endPC = mCurModule->mCodeBase + mCurModule->mLength;
|
endPC = mCurModule->mCodeBase + mCurModule->mLength;
|
||||||
mLocals = prev->mLocals;
|
mLocals = prev->mLocals;
|
||||||
mStack = prev->mStack;
|
mStack = prev->mStack;
|
||||||
mStackTop = 1; // just the exception object remains
|
|
||||||
mStackMax = mCurModule->mStackDepth;
|
mStackMax = mCurModule->mStackDepth;
|
||||||
mArgumentBase = prev->mArgumentBase;
|
mArgumentBase = prev->mArgumentBase;
|
||||||
mThis = prev->mThis;
|
mThis = prev->mThis;
|
||||||
|
@ -1684,10 +1680,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
||||||
pushValue(x);
|
pushValue(x);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
reportError(Exception::uncaughtError, "No handler for throw");
|
throw jsx; //reportError(Exception::uncaughtError, "No handler for throw");
|
||||||
}
|
|
||||||
catch (Exception x) {
|
|
||||||
throw x;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -2259,7 +2252,7 @@ JSValue JSValue::valueToNumber(Context *cx, const JSValue& value)
|
||||||
return JSValue(stringToNumber(value.string));
|
return JSValue(stringToNumber(value.string));
|
||||||
case object_tag:
|
case object_tag:
|
||||||
case function_tag:
|
case function_tag:
|
||||||
return value.toPrimitive(cx, NoHint).toNumber(cx);
|
return value.toPrimitive(cx, NumberHint).toNumber(cx);
|
||||||
case boolean_tag:
|
case boolean_tag:
|
||||||
return JSValue((value.boolean) ? 1.0 : 0.0);
|
return JSValue((value.boolean) ? 1.0 : 0.0);
|
||||||
case undefined_tag:
|
case undefined_tag:
|
||||||
|
@ -2326,7 +2319,7 @@ JSValue JSValue::valueToString(Context *cx, const JSValue& value)
|
||||||
}
|
}
|
||||||
if (target)
|
if (target)
|
||||||
return cx->invokeFunction(target, value, NULL, 0);
|
return cx->invokeFunction(target, value, NULL, 0);
|
||||||
throw new Exception(Exception::runtimeError, "toString"); // XXX
|
cx->reportError(Exception::runtimeError, "toString"); // XXX
|
||||||
return kUndefinedValue; // keep compilers happy
|
return kUndefinedValue; // keep compilers happy
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2396,7 +2389,7 @@ JSValue JSValue::toPrimitive(Context *cx, Hint hint) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new Exception(Exception::runtimeError, "toPrimitive"); // XXX
|
cx->reportError(Exception::runtimeError, "toPrimitive"); // XXX
|
||||||
return kUndefinedValue;
|
return kUndefinedValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,13 @@ JSType *Attribute_Type;
|
||||||
JSType *NamedArgument_Type;
|
JSType *NamedArgument_Type;
|
||||||
JSArrayType *Array_Type;
|
JSArrayType *Array_Type;
|
||||||
JSType *Date_Type;
|
JSType *Date_Type;
|
||||||
|
JSType *Error_Type;
|
||||||
|
JSType *EvalError_Type;
|
||||||
|
JSType *RangeError_Type;
|
||||||
|
JSType *ReferenceError_Type;
|
||||||
|
JSType *SyntaxError_Type;
|
||||||
|
JSType *TypeError_Type;
|
||||||
|
JSType *UriError_Type;
|
||||||
|
|
||||||
|
|
||||||
Attribute *Context::executeAttributes(ExprNode *attr)
|
Attribute *Context::executeAttributes(ExprNode *attr)
|
||||||
|
@ -672,6 +679,18 @@ void ScopeChain::setNameValue(Context *cx, const String& name, AttributeStmtNode
|
||||||
cx->getGlobalObject()->defineVariable(cx, name, attr, Object_Type, v);
|
cx->getGlobalObject()->defineVariable(cx, name, attr, Object_Type, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ScopeChain::deleteName(Context *cx, const String& name, AttributeStmtNode *attr)
|
||||||
|
{
|
||||||
|
NamespaceList *names = (attr) ? attr->attributeValue->mNamespaceList : NULL;
|
||||||
|
for (ScopeScanner s = mScopeStack.rbegin(), end = mScopeStack.rend(); (s != end); s++)
|
||||||
|
{
|
||||||
|
PropertyIterator i;
|
||||||
|
if ((*s)->hasOwnProperty(name, names, Read, &i))
|
||||||
|
return (*s)->deleteProperty(name, names);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
inline char narrow(char16 ch) { return char(ch); }
|
inline char narrow(char16 ch) { return char(ch); }
|
||||||
|
|
||||||
JSObject *ScopeChain::getNameValue(Context *cx, const String& name, AttributeStmtNode *attr)
|
JSObject *ScopeChain::getNameValue(Context *cx, const String& name, AttributeStmtNode *attr)
|
||||||
|
@ -989,8 +1008,8 @@ void ScopeChain::collectNames(StmtNode *p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case StmtNode::If:
|
|
||||||
case StmtNode::With:
|
case StmtNode::With:
|
||||||
|
case StmtNode::If:
|
||||||
case StmtNode::DoWhile:
|
case StmtNode::DoWhile:
|
||||||
case StmtNode::While:
|
case StmtNode::While:
|
||||||
{
|
{
|
||||||
|
@ -1008,13 +1027,16 @@ void ScopeChain::collectNames(StmtNode *p)
|
||||||
case StmtNode::Try:
|
case StmtNode::Try:
|
||||||
{
|
{
|
||||||
TryStmtNode *t = checked_cast<TryStmtNode *>(p);
|
TryStmtNode *t = checked_cast<TryStmtNode *>(p);
|
||||||
|
collectNames(t->stmt);
|
||||||
if (t->catches) {
|
if (t->catches) {
|
||||||
CatchClause *c = t->catches;
|
CatchClause *c = t->catches;
|
||||||
while (c) {
|
while (c) {
|
||||||
|
collectNames(c->stmt);
|
||||||
c->prop = defineVariable(m_cx, c->name, NULL, NULL);
|
c->prop = defineVariable(m_cx, c->name, NULL, NULL);
|
||||||
c = c->next;
|
c = c->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (t->finally) collectNames(t->finally);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case StmtNode::For:
|
case StmtNode::For:
|
||||||
|
@ -1046,6 +1068,7 @@ void ScopeChain::collectNames(StmtNode *p)
|
||||||
v->prop = defineStaticVariable(m_cx, *v->name, vs, NULL);
|
v->prop = defineStaticVariable(m_cx, *v->name, vs, NULL);
|
||||||
else
|
else
|
||||||
v->prop = defineVariable(m_cx, *v->name, vs, NULL);
|
v->prop = defineVariable(m_cx, *v->name, vs, NULL);
|
||||||
|
v->scope = mScopeStack.back();
|
||||||
v = v->next;
|
v = v->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1590,17 +1613,20 @@ void Context::buildRuntimeForStmt(StmtNode *p)
|
||||||
case StmtNode::Try:
|
case StmtNode::Try:
|
||||||
{
|
{
|
||||||
TryStmtNode *t = checked_cast<TryStmtNode *>(p);
|
TryStmtNode *t = checked_cast<TryStmtNode *>(p);
|
||||||
|
buildRuntimeForStmt(t->stmt);
|
||||||
if (t->catches) {
|
if (t->catches) {
|
||||||
CatchClause *c = t->catches;
|
CatchClause *c = t->catches;
|
||||||
while (c) {
|
while (c) {
|
||||||
|
buildRuntimeForStmt(c->stmt);
|
||||||
c->prop->mType = mScopeChain->extractType(c->type);
|
c->prop->mType = mScopeChain->extractType(c->type);
|
||||||
c = c->next;
|
c = c->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (t->finally) buildRuntimeForStmt(t->finally);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case StmtNode::If:
|
|
||||||
case StmtNode::With:
|
case StmtNode::With:
|
||||||
|
case StmtNode::If:
|
||||||
case StmtNode::DoWhile:
|
case StmtNode::DoWhile:
|
||||||
case StmtNode::While:
|
case StmtNode::While:
|
||||||
{
|
{
|
||||||
|
@ -1745,7 +1771,7 @@ static JSValue Object_Constructor(Context *cx, const JSValue& thisValue, JSValue
|
||||||
JSValue thatValue = thisValue; // incoming 'new this' potentially supplied by constructor sequence
|
JSValue thatValue = thisValue; // incoming 'new this' potentially supplied by constructor sequence
|
||||||
|
|
||||||
if (argc != 0) {
|
if (argc != 0) {
|
||||||
if (argv[0].isObject())
|
if (argv[0].isObject() || argv[0].isFunction() || argv[0].isType())
|
||||||
thatValue = argv[0];
|
thatValue = argv[0];
|
||||||
else
|
else
|
||||||
if (argv[0].isString() || argv[0].isBool() || argv[0].isNumber())
|
if (argv[0].isString() || argv[0].isBool() || argv[0].isNumber())
|
||||||
|
@ -2030,6 +2056,14 @@ static JSValue Boolean_Constructor(Context *cx, const JSValue& thisValue, JSValu
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static JSValue Boolean_TypeCast(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
|
||||||
|
{
|
||||||
|
if (argc == 0)
|
||||||
|
return kFalseValue;
|
||||||
|
else
|
||||||
|
return argv[0].toBoolean(cx);
|
||||||
|
}
|
||||||
|
|
||||||
static JSValue Boolean_toString(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
|
static JSValue Boolean_toString(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
|
||||||
{
|
{
|
||||||
ASSERT(thisValue.isObject());
|
ASSERT(thisValue.isObject());
|
||||||
|
@ -2054,6 +2088,76 @@ static JSValue Boolean_valueOf(Context *cx, const JSValue& thisValue, JSValue *
|
||||||
return kFalseValue;
|
return kFalseValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static JSValue GenericError_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc, JSType *errType)
|
||||||
|
{
|
||||||
|
JSValue v = thisValue;
|
||||||
|
if (v.isNull())
|
||||||
|
v = errType->newInstance(cx);
|
||||||
|
ASSERT(v.isObject());
|
||||||
|
JSObject *thisObj = v.object;
|
||||||
|
JSValue msg;
|
||||||
|
if (argc > 0)
|
||||||
|
msg = argv[0].toString(cx);
|
||||||
|
else
|
||||||
|
msg = JSValue(&cx->Empty_StringAtom);
|
||||||
|
thisObj->defineVariable(cx, cx->Message_StringAtom, NULL, Property::NoAttribute, String_Type, msg);
|
||||||
|
thisObj->defineVariable(cx, cx->Name_StringAtom, NULL, Property::NoAttribute, String_Type, JSValue(errType->mClassName));
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue Error_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
|
||||||
|
{
|
||||||
|
return GenericError_Constructor(cx, thisValue, argv, argc, Error_Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSValue Error_toString(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
|
||||||
|
{
|
||||||
|
ContextStackReplacement csr(cx);
|
||||||
|
|
||||||
|
ASSERT(thisValue.isObject());
|
||||||
|
JSObject *thisObj = thisValue.object;
|
||||||
|
if ((thisObj->mType != Error_Type) && !thisObj->mType->derivesFrom(Error_Type))
|
||||||
|
cx->reportError(Exception::typeError, "Error.toString can only be applied to Error objects");
|
||||||
|
thisObj->getProperty(cx, cx->Message_StringAtom, CURRENT_ATTR);
|
||||||
|
JSValue msg = cx->popValue();
|
||||||
|
thisObj->getProperty(cx, cx->Name_StringAtom, CURRENT_ATTR);
|
||||||
|
JSValue name = cx->popValue();
|
||||||
|
|
||||||
|
String *result = new String(*name.toString(cx).string + ":" + *msg.toString(cx).string);
|
||||||
|
return JSValue(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue EvalError_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
|
||||||
|
{
|
||||||
|
return GenericError_Constructor(cx, thisValue, argv, argc, EvalError_Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue RangeError_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
|
||||||
|
{
|
||||||
|
return GenericError_Constructor(cx, thisValue, argv, argc, RangeError_Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue ReferenceError_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
|
||||||
|
{
|
||||||
|
return GenericError_Constructor(cx, thisValue, argv, argc, ReferenceError_Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue SyntaxError_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
|
||||||
|
{
|
||||||
|
return GenericError_Constructor(cx, thisValue, argv, argc, SyntaxError_Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue TypeError_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
|
||||||
|
{
|
||||||
|
return GenericError_Constructor(cx, thisValue, argv, argc, TypeError_Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue UriError_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
|
||||||
|
{
|
||||||
|
return GenericError_Constructor(cx, thisValue, argv, argc, UriError_Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static JSValue ExtendAttribute_Invoke(Context * /*cx*/, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
|
static JSValue ExtendAttribute_Invoke(Context * /*cx*/, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
|
||||||
{
|
{
|
||||||
ASSERT(argc == 1);
|
ASSERT(argc == 1);
|
||||||
|
@ -2065,15 +2169,18 @@ static JSValue ExtendAttribute_Invoke(Context * /*cx*/, const JSValue& /*thisVal
|
||||||
return JSValue(x);
|
return JSValue(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSValue GlobalObject_Eval(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
|
static JSValue GlobalObject_Eval(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
|
||||||
{
|
{
|
||||||
if (!argv[0].isString())
|
if (argc > 0) {
|
||||||
return argv[0];
|
if (!argv[0].isString())
|
||||||
const String *sourceStr = argv[0].toString(cx).string;
|
return argv[0];
|
||||||
|
const String *sourceStr = argv[0].toString(cx).string;
|
||||||
|
|
||||||
Activation *prev = cx->mActivationStack.top();
|
Activation *prev = cx->mActivationStack.top();
|
||||||
|
|
||||||
return cx->readEvalString(*sourceStr, widenCString("eval source"), cx->mScopeChain, prev->mThis);
|
return cx->readEvalString(*sourceStr, widenCString("eval source"), cx->mScopeChain, prev->mThis);
|
||||||
|
}
|
||||||
|
return kUndefinedValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSValue GlobalObject_ParseInt(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
|
static JSValue GlobalObject_ParseInt(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
|
||||||
|
@ -2125,6 +2232,149 @@ static JSValue GlobalObject_isFinite(Context *cx, const JSValue& /*thisValue*/,
|
||||||
return kFalseValue;
|
return kFalseValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stuff to emulate the old libmocha escape, which took a second argument
|
||||||
|
* giving the type of escape to perform. Retained for compatibility, and
|
||||||
|
* copied here to avoid reliance on net.h, mkparse.c/NET_EscapeBytes.
|
||||||
|
*/
|
||||||
|
#define URL_XALPHAS ((uint8) 1)
|
||||||
|
#define URL_XPALPHAS ((uint8) 2)
|
||||||
|
#define URL_PATH ((uint8) 4)
|
||||||
|
|
||||||
|
static const uint8 urlCharType[256] =
|
||||||
|
/* Bit 0 xalpha -- the alphas
|
||||||
|
* Bit 1 xpalpha -- as xalpha but
|
||||||
|
* converts spaces to plus and plus to %20
|
||||||
|
* Bit 2 ... path -- as xalphas but doesn't escape '/'
|
||||||
|
*/
|
||||||
|
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
||||||
|
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x */
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1x */
|
||||||
|
0,0,0,0,0,0,0,0,0,0,7,4,0,7,7,4, /* 2x !"#$%&'()*+,-./ */
|
||||||
|
7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */
|
||||||
|
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 4x @ABCDEFGHIJKLMNO */
|
||||||
|
7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7, /* 5X PQRSTUVWXYZ[\]^_ */
|
||||||
|
0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 6x `abcdefghijklmno */
|
||||||
|
7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0, /* 7X pqrstuvwxyz{\}~ DEL */
|
||||||
|
0, };
|
||||||
|
|
||||||
|
/* This matches the ECMA escape set when mask is 7 (default.) */
|
||||||
|
|
||||||
|
#define IS_OK(C, mask) (urlCharType[((uint8) (C))] & (mask))
|
||||||
|
|
||||||
|
/* See ECMA-262 15.1.2.4. */
|
||||||
|
static JSValue GlobalObject_escape(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
|
||||||
|
{
|
||||||
|
if (argc > 0) {
|
||||||
|
uint32 i, ni, length, newlength;
|
||||||
|
char16 ch;
|
||||||
|
|
||||||
|
const char digits[] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
||||||
|
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||||
|
|
||||||
|
uint32 mask = URL_XALPHAS | URL_XPALPHAS | URL_PATH;
|
||||||
|
if (argc > 1) {
|
||||||
|
float64 d = argv[1].toNumber(cx).f64;
|
||||||
|
if (!JSDOUBLE_IS_FINITE(d) || (mask = (uint32)d) != d || mask & ~(URL_XALPHAS | URL_XPALPHAS | URL_PATH))
|
||||||
|
cx->reportError(Exception::runtimeError, "Bad string mask for escape");
|
||||||
|
}
|
||||||
|
|
||||||
|
const String *str = argv[0].toString(cx).string;
|
||||||
|
|
||||||
|
const char16 *chars = str->begin();
|
||||||
|
length = newlength = str->size();
|
||||||
|
|
||||||
|
/* Take a first pass and see how big the result string will need to be. */
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
if ((ch = chars[i]) < 128 && IS_OK(ch, mask))
|
||||||
|
continue;
|
||||||
|
if (ch < 256) {
|
||||||
|
if (mask == URL_XPALPHAS && ch == ' ')
|
||||||
|
continue; /* The character will be encoded as '+' */
|
||||||
|
newlength += 2; /* The character will be encoded as %XX */
|
||||||
|
} else {
|
||||||
|
newlength += 5; /* The character will be encoded as %uXXXX */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char16 *newchars = new char16[newlength + 1];
|
||||||
|
for (i = 0, ni = 0; i < length; i++) {
|
||||||
|
if ((ch = chars[i]) < 128 && IS_OK(ch, mask)) {
|
||||||
|
newchars[ni++] = ch;
|
||||||
|
} else if (ch < 256) {
|
||||||
|
if (mask == URL_XPALPHAS && ch == ' ') {
|
||||||
|
newchars[ni++] = '+'; /* convert spaces to pluses */
|
||||||
|
} else {
|
||||||
|
newchars[ni++] = '%';
|
||||||
|
newchars[ni++] = digits[ch >> 4];
|
||||||
|
newchars[ni++] = digits[ch & 0xF];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newchars[ni++] = '%';
|
||||||
|
newchars[ni++] = 'u';
|
||||||
|
newchars[ni++] = digits[ch >> 12];
|
||||||
|
newchars[ni++] = digits[(ch & 0xF00) >> 8];
|
||||||
|
newchars[ni++] = digits[(ch & 0xF0) >> 4];
|
||||||
|
newchars[ni++] = digits[ch & 0xF];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ASSERT(ni == newlength);
|
||||||
|
newchars[newlength] = 0;
|
||||||
|
|
||||||
|
String *result = new String(newchars, newlength);
|
||||||
|
delete[] newchars;
|
||||||
|
return JSValue(result);
|
||||||
|
}
|
||||||
|
return JSValue(&cx->Undefined_StringAtom);
|
||||||
|
}
|
||||||
|
#undef IS_OK
|
||||||
|
|
||||||
|
/* See ECMA-262 15.1.2.5 */
|
||||||
|
static JSValue GlobalObject_unescape(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
|
||||||
|
{
|
||||||
|
if (argc > 0) {
|
||||||
|
uint32 i, ni;
|
||||||
|
char16 ch;
|
||||||
|
|
||||||
|
const String *str = argv[0].toString(cx).string;
|
||||||
|
|
||||||
|
const char16 *chars = str->begin();
|
||||||
|
uint32 length = str->size();
|
||||||
|
|
||||||
|
/* Don't bother allocating less space for the new string. */
|
||||||
|
char16 *newchars = new char16[length + 1];
|
||||||
|
ni = i = 0;
|
||||||
|
while (i < length) {
|
||||||
|
uint hexValue[4];
|
||||||
|
ch = chars[i++];
|
||||||
|
if (ch == '%') {
|
||||||
|
if (i + 1 < length &&
|
||||||
|
isASCIIHexDigit(chars[i], hexValue[0]) && isASCIIHexDigit(chars[i + 1], hexValue[1]))
|
||||||
|
{
|
||||||
|
ch = hexValue[0] * 16 + hexValue[1];
|
||||||
|
i += 2;
|
||||||
|
} else if (i + 4 < length && chars[i] == 'u' &&
|
||||||
|
isASCIIHexDigit(chars[i + 1], hexValue[0]) && isASCIIHexDigit(chars[i + 2], hexValue[1]) &&
|
||||||
|
isASCIIHexDigit(chars[i + 3], hexValue[2]) && isASCIIHexDigit(chars[i + 4], hexValue[3]))
|
||||||
|
{
|
||||||
|
ch = (((((hexValue[0] << 4)
|
||||||
|
+ hexValue[1]) << 4)
|
||||||
|
+ hexValue[2]) << 4)
|
||||||
|
+ hexValue[3];
|
||||||
|
i += 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newchars[ni++] = ch;
|
||||||
|
}
|
||||||
|
newchars[ni] = 0;
|
||||||
|
|
||||||
|
String *result = new String(newchars, ni);
|
||||||
|
delete[] newchars;
|
||||||
|
return JSValue(result);
|
||||||
|
}
|
||||||
|
return JSValue(&cx->Undefined_StringAtom);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
JSFunction::JSFunction(Context *cx, JSType *resultType, ScopeChain *scopeChain)
|
JSFunction::JSFunction(Context *cx, JSType *resultType, ScopeChain *scopeChain)
|
||||||
: JSObject(Function_Type),
|
: JSObject(Function_Type),
|
||||||
|
@ -2276,20 +2526,27 @@ void Context::initBuiltins()
|
||||||
{
|
{
|
||||||
ClassDef builtInClasses[] =
|
ClassDef builtInClasses[] =
|
||||||
{
|
{
|
||||||
{ "Object", Object_Constructor, &kUndefinedValue },
|
{ "Object", Object_Constructor, &kUndefinedValue },
|
||||||
{ "Type", NULL, &kNullValue },
|
{ "Type", NULL, &kNullValue },
|
||||||
{ "Function", Function_Constructor, &kNullValue },
|
{ "Function", Function_Constructor, &kNullValue },
|
||||||
{ "Number", Number_Constructor, &kPositiveZero },
|
{ "Number", Number_Constructor, &kPositiveZero },
|
||||||
{ "Integer", Integer_Constructor, &kPositiveZero },
|
{ "Integer", Integer_Constructor, &kPositiveZero },
|
||||||
{ "String", String_Constructor, &kNullValue },
|
{ "String", String_Constructor, &kNullValue },
|
||||||
{ "Array", Array_Constructor, &kNullValue },
|
{ "Array", Array_Constructor, &kNullValue },
|
||||||
{ "Boolean", Boolean_Constructor, &kFalseValue },
|
{ "Boolean", Boolean_Constructor, &kFalseValue },
|
||||||
{ "Void", NULL, &kUndefinedValue },
|
{ "Void", NULL, &kUndefinedValue },
|
||||||
{ "Unit", NULL, &kNullValue },
|
{ "Unit", NULL, &kNullValue },
|
||||||
{ "Attribute", NULL, &kNullValue },
|
{ "Attribute", NULL, &kNullValue },
|
||||||
{ "NamedArgument", NULL, &kNullValue },
|
{ "NamedArgument", NULL, &kNullValue },
|
||||||
{ "Date", Date_Constructor, &kPositiveZero },
|
{ "Date", Date_Constructor, &kPositiveZero },
|
||||||
{ "Null", NULL, &kNullValue },
|
{ "Null", NULL, &kNullValue },
|
||||||
|
{ "Error", Error_Constructor, &kNullValue },
|
||||||
|
{ "EvalError", EvalError_Constructor, &kNullValue },
|
||||||
|
{ "RangeError", RangeError_Constructor, &kNullValue },
|
||||||
|
{ "ReferenceError", ReferenceError_Constructor, &kNullValue },
|
||||||
|
{ "SyntaxError", SyntaxError_Constructor, &kNullValue },
|
||||||
|
{ "TypeError", TypeError_Constructor, &kNullValue },
|
||||||
|
{ "UriError", UriError_Constructor, &kNullValue },
|
||||||
};
|
};
|
||||||
|
|
||||||
Object_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[0].name)], NULL);
|
Object_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[0].name)], NULL);
|
||||||
|
@ -2334,6 +2591,13 @@ void Context::initBuiltins()
|
||||||
NamedArgument_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[11].name)], Object_Type);
|
NamedArgument_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[11].name)], Object_Type);
|
||||||
Date_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[12].name)], Object_Type);
|
Date_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[12].name)], Object_Type);
|
||||||
Null_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[13].name)], Object_Type);
|
Null_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[13].name)], Object_Type);
|
||||||
|
Error_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[14].name)], Object_Type);
|
||||||
|
EvalError_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[15].name)], Error_Type);
|
||||||
|
RangeError_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[16].name)], Error_Type);
|
||||||
|
ReferenceError_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[17].name)], Error_Type);
|
||||||
|
SyntaxError_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[18].name)], Error_Type);
|
||||||
|
TypeError_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[19].name)], Error_Type);
|
||||||
|
UriError_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[20].name)], Error_Type);
|
||||||
|
|
||||||
String_Type->defineVariable(this, FromCharCode_StringAtom, NULL, String_Type, JSValue(new JSFunction(this, String_fromCharCode, String_Type)));
|
String_Type->defineVariable(this, FromCharCode_StringAtom, NULL, String_Type, JSValue(new JSFunction(this, String_fromCharCode, String_Type)));
|
||||||
|
|
||||||
|
@ -2374,6 +2638,12 @@ void Context::initBuiltins()
|
||||||
{ "valueOf", Number_Type, 0, Boolean_valueOf },
|
{ "valueOf", Number_Type, 0, Boolean_valueOf },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
ProtoFunDef errorProtos[] =
|
||||||
|
{
|
||||||
|
{ "toString", String_Type, 0, Error_toString },
|
||||||
|
{ "toSource", String_Type, 0, Error_toString },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
|
||||||
ASSERT(mGlobal);
|
ASSERT(mGlobal);
|
||||||
*mGlobal = Object_Type->newInstance(this);
|
*mGlobal = Object_Type->newInstance(this);
|
||||||
|
@ -2392,9 +2662,17 @@ void Context::initBuiltins()
|
||||||
initClass(NamedArgument_Type, &builtInClasses[11], NULL);
|
initClass(NamedArgument_Type, &builtInClasses[11], NULL);
|
||||||
initClass(Date_Type, &builtInClasses[12], getDateProtos() );
|
initClass(Date_Type, &builtInClasses[12], getDateProtos() );
|
||||||
initClass(Null_Type, &builtInClasses[13], NULL);
|
initClass(Null_Type, &builtInClasses[13], NULL);
|
||||||
|
initClass(Error_Type, &builtInClasses[14], new PrototypeFunctions(&errorProtos[0]));
|
||||||
|
initClass(EvalError_Type, &builtInClasses[15], new PrototypeFunctions(&errorProtos[0]));
|
||||||
|
initClass(RangeError_Type, &builtInClasses[16], new PrototypeFunctions(&errorProtos[0]));
|
||||||
|
initClass(ReferenceError_Type, &builtInClasses[17], new PrototypeFunctions(&errorProtos[0]));
|
||||||
|
initClass(SyntaxError_Type, &builtInClasses[18], new PrototypeFunctions(&errorProtos[0]));
|
||||||
|
initClass(TypeError_Type, &builtInClasses[19], new PrototypeFunctions(&errorProtos[0]));
|
||||||
|
initClass(UriError_Type, &builtInClasses[20], new PrototypeFunctions(&errorProtos[0]));
|
||||||
|
|
||||||
Type_Type->defineUnaryOperator(Index, new JSFunction(this, arrayMaker, Type_Type));
|
Type_Type->defineUnaryOperator(Index, new JSFunction(this, arrayMaker, Type_Type));
|
||||||
|
|
||||||
|
Object_Type->mTypeCast = new JSFunction(this, Object_Constructor, Object_Type);
|
||||||
Function_Type->mTypeCast = new JSFunction(this, Function_Constructor, Object_Type);
|
Function_Type->mTypeCast = new JSFunction(this, Function_Constructor, Object_Type);
|
||||||
|
|
||||||
Number_Type->mTypeCast = new JSFunction(this, Number_TypeCast, Number_Type);
|
Number_Type->mTypeCast = new JSFunction(this, Number_TypeCast, Number_Type);
|
||||||
|
@ -2403,12 +2681,16 @@ void Context::initBuiltins()
|
||||||
Array_Type->defineUnaryOperator(IndexEqual, new JSFunction(this, Array_SetElement, Object_Type));
|
Array_Type->defineUnaryOperator(IndexEqual, new JSFunction(this, Array_SetElement, Object_Type));
|
||||||
Array_Type->mTypeCast = new JSFunction(this, Array_Constructor, Array_Type);
|
Array_Type->mTypeCast = new JSFunction(this, Array_Constructor, Array_Type);
|
||||||
|
|
||||||
|
Boolean_Type->mTypeCast = new JSFunction(this, Boolean_TypeCast, Boolean_Type);
|
||||||
|
|
||||||
Date_Type->mTypeCast = new JSFunction(this, Date_TypeCast, String_Type);
|
Date_Type->mTypeCast = new JSFunction(this, Date_TypeCast, String_Type);
|
||||||
Date_Type->defineStaticMethod(this, widenCString("parse"), NULL, new JSFunction(this, Date_parse, Number_Type));
|
Date_Type->defineStaticMethod(this, widenCString("parse"), NULL, new JSFunction(this, Date_parse, Number_Type));
|
||||||
Date_Type->defineStaticMethod(this, widenCString("UTC"), NULL, new JSFunction(this, Date_UTC, Number_Type));
|
Date_Type->defineStaticMethod(this, widenCString("UTC"), NULL, new JSFunction(this, Date_UTC, Number_Type));
|
||||||
|
|
||||||
String_Type->mTypeCast = new JSFunction(this, String_TypeCast, String_Type);
|
String_Type->mTypeCast = new JSFunction(this, String_TypeCast, String_Type);
|
||||||
|
|
||||||
|
Error_Type->mTypeCast = new JSFunction(this, Error_Constructor, Error_Type);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2509,6 +2791,15 @@ Context::Context(JSObject **global, World &world, Arena &a, Pragma::Flags flags)
|
||||||
Infinity_StringAtom (world.identifiers["Infinity"]),
|
Infinity_StringAtom (world.identifiers["Infinity"]),
|
||||||
Empty_StringAtom (world.identifiers[""]),
|
Empty_StringAtom (world.identifiers[""]),
|
||||||
Arguments_StringAtom (world.identifiers["arguments"]),
|
Arguments_StringAtom (world.identifiers["arguments"]),
|
||||||
|
Message_StringAtom (world.identifiers["message"]),
|
||||||
|
Name_StringAtom (world.identifiers["name"]),
|
||||||
|
Error_StringAtom (world.identifiers["Error"]),
|
||||||
|
EvalError_StringAtom (world.identifiers["EvalError"]),
|
||||||
|
RangeError_StringAtom (world.identifiers["RangeError"]),
|
||||||
|
ReferenceError_StringAtom (world.identifiers["ReferenceError"]),
|
||||||
|
SyntaxError_StringAtom (world.identifiers["SyntaxError"]),
|
||||||
|
TypeError_StringAtom (world.identifiers["TypeError"]),
|
||||||
|
UriError_StringAtom (world.identifiers["UriError"]),
|
||||||
|
|
||||||
mWorld(world),
|
mWorld(world),
|
||||||
mScopeChain(NULL),
|
mScopeChain(NULL),
|
||||||
|
@ -2596,6 +2887,8 @@ Context::Context(JSObject **global, World &world, Arena &a, Pragma::Flags flags)
|
||||||
{ "parseFloat", Number_Type, 2, GlobalObject_ParseFloat },
|
{ "parseFloat", Number_Type, 2, GlobalObject_ParseFloat },
|
||||||
{ "isNaN", Boolean_Type, 2, GlobalObject_isNaN },
|
{ "isNaN", Boolean_Type, 2, GlobalObject_isNaN },
|
||||||
{ "isFinite", Boolean_Type, 2, GlobalObject_isFinite },
|
{ "isFinite", Boolean_Type, 2, GlobalObject_isFinite },
|
||||||
|
{ "escape", String_Type, 1, GlobalObject_escape },
|
||||||
|
{ "unescape", String_Type, 1, GlobalObject_unescape },
|
||||||
};
|
};
|
||||||
|
|
||||||
for (i = 0; i < (sizeof(globalObjectFunctions) / sizeof(ProtoFunDef)); i++) {
|
for (i = 0; i < (sizeof(globalObjectFunctions) / sizeof(ProtoFunDef)); i++) {
|
||||||
|
@ -2605,18 +2898,6 @@ Context::Context(JSObject **global, World &world, Arena &a, Pragma::Flags flags)
|
||||||
getGlobalObject()->defineVariable(this, widenCString(globalObjectFunctions[i].name), (NamespaceList *)(NULL), Property::NoAttribute, globalObjectFunctions[i].result, JSValue(x));
|
getGlobalObject()->defineVariable(this, widenCString(globalObjectFunctions[i].name), (NamespaceList *)(NULL), Property::NoAttribute, globalObjectFunctions[i].result, JSValue(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
x = new JSFunction(GlobalObject_Eval, Object_Type);
|
|
||||||
x->setArgCounts(1, 0, false);
|
|
||||||
x->setIsPrototype(true);
|
|
||||||
getGlobalObject()->defineVariable(this, Eval_StringAtom, (NamespaceList *)(NULL), Object_Type, JSValue(x));
|
|
||||||
|
|
||||||
x = new JSFunction(GlobalObject_ParseInt, Number_Type);
|
|
||||||
x->setArgCounts(2, 0, false);
|
|
||||||
x->setIsPrototype(true);
|
|
||||||
getGlobalObject()->defineVariable(this, widenCString("parseInt"), (NamespaceList *)(NULL), Object_Type, JSValue(x));
|
|
||||||
*/
|
|
||||||
|
|
||||||
getGlobalObject()->defineVariable(this, Undefined_StringAtom, (NamespaceList *)(NULL), Property::NoAttribute, Void_Type, kUndefinedValue);
|
getGlobalObject()->defineVariable(this, Undefined_StringAtom, (NamespaceList *)(NULL), Property::NoAttribute, Void_Type, kUndefinedValue);
|
||||||
getGlobalObject()->defineVariable(this, NaN_StringAtom, (NamespaceList *)(NULL), Property::NoAttribute, Void_Type, kNaNValue);
|
getGlobalObject()->defineVariable(this, NaN_StringAtom, (NamespaceList *)(NULL), Property::NoAttribute, Void_Type, kNaNValue);
|
||||||
getGlobalObject()->defineVariable(this, Infinity_StringAtom, (NamespaceList *)(NULL), Property::NoAttribute, Void_Type, kPositiveInfinity);
|
getGlobalObject()->defineVariable(this, Infinity_StringAtom, (NamespaceList *)(NULL), Property::NoAttribute, Void_Type, kPositiveInfinity);
|
||||||
|
|
|
@ -1083,12 +1083,14 @@ XXX ...couldn't get this to work...
|
||||||
return top->hasProperty(name, names, acc, p);
|
return top->hasProperty(name, names, acc, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool deleteName(Context *cx, const String& name, AttributeStmtNode *attr);
|
||||||
|
/*
|
||||||
bool hasOwnProperty(const String& name, NamespaceList *names, Access acc, PropertyIterator *p)
|
bool hasOwnProperty(const String& name, NamespaceList *names, Access acc, PropertyIterator *p)
|
||||||
{
|
{
|
||||||
JSObject *top = mScopeStack.back();
|
JSObject *top = mScopeStack.back();
|
||||||
return top->hasOwnProperty(name, names, acc, p);
|
return top->hasOwnProperty(name, names, acc, p);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
// delete a property from the top object (already know it's there)
|
// delete a property from the top object (already know it's there)
|
||||||
bool deleteProperty(const String &name, NamespaceList *names)
|
bool deleteProperty(const String &name, NamespaceList *names)
|
||||||
{
|
{
|
||||||
|
@ -1367,8 +1369,18 @@ XXX ...couldn't get this to work...
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Attribute;
|
|
||||||
|
|
||||||
|
// provide access to the Error object constructors so that runtime exceptions
|
||||||
|
// can be constructed for Javascript catches.
|
||||||
|
extern JSValue Error_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc);
|
||||||
|
extern JSValue EvalError_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc);
|
||||||
|
extern JSValue RangeError_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc);
|
||||||
|
extern JSValue ReferenceError_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc);
|
||||||
|
extern JSValue SyntaxError_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc);
|
||||||
|
extern JSValue TypeError_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc);
|
||||||
|
extern JSValue UriError_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc);
|
||||||
|
|
||||||
|
class Attribute;
|
||||||
|
|
||||||
class Context {
|
class Context {
|
||||||
public:
|
public:
|
||||||
|
@ -1444,6 +1456,15 @@ XXX ...couldn't get this to work...
|
||||||
StringAtom& Infinity_StringAtom;
|
StringAtom& Infinity_StringAtom;
|
||||||
StringAtom& Empty_StringAtom;
|
StringAtom& Empty_StringAtom;
|
||||||
StringAtom& Arguments_StringAtom;
|
StringAtom& Arguments_StringAtom;
|
||||||
|
StringAtom& Message_StringAtom;
|
||||||
|
StringAtom& Name_StringAtom;
|
||||||
|
StringAtom& Error_StringAtom;
|
||||||
|
StringAtom& EvalError_StringAtom;
|
||||||
|
StringAtom& RangeError_StringAtom;
|
||||||
|
StringAtom& ReferenceError_StringAtom;
|
||||||
|
StringAtom& SyntaxError_StringAtom;
|
||||||
|
StringAtom& TypeError_StringAtom;
|
||||||
|
StringAtom& UriError_StringAtom;
|
||||||
|
|
||||||
void initBuiltins();
|
void initBuiltins();
|
||||||
void initClass(JSType *type, ClassDef *cdef, PrototypeFunctions *pdef);
|
void initClass(JSType *type, ClassDef *cdef, PrototypeFunctions *pdef);
|
||||||
|
@ -1580,6 +1601,10 @@ XXX ...couldn't get this to work...
|
||||||
|
|
||||||
OperatorList mOperatorTable[OperatorCount];
|
OperatorList mOperatorTable[OperatorCount];
|
||||||
|
|
||||||
|
typedef String PackageName;
|
||||||
|
typedef std::vector<PackageName> PackageList;
|
||||||
|
|
||||||
|
PackageList mPackages; // the currently loaded packages, mPackages.back() is the current package
|
||||||
|
|
||||||
JSValue readEvalFile(const String& fileName);
|
JSValue readEvalFile(const String& fileName);
|
||||||
JSValue readEvalString(const String &str, const String& fileName, ScopeChain *scopeChain, const JSValue& thisValue);
|
JSValue readEvalString(const String &str, const String& fileName, ScopeChain *scopeChain, const JSValue& thisValue);
|
||||||
|
|
|
@ -407,7 +407,7 @@ typedef struct QSortArgs {
|
||||||
CompareArgs *arg;
|
CompareArgs *arg;
|
||||||
} QSortArgs;
|
} QSortArgs;
|
||||||
|
|
||||||
static int sort_compare(JSValue *a, JSValue *b, CompareArgs *arg);
|
static int32 sort_compare(JSValue *a, JSValue *b, CompareArgs *arg);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
js_qsort_r(QSortArgs *qa, int lo, int hi)
|
js_qsort_r(QSortArgs *qa, int lo, int hi)
|
||||||
|
@ -472,15 +472,15 @@ static void js_qsort(JSValue *vec, size_t nel, CompareArgs *arg)
|
||||||
delete(pivot);
|
delete(pivot);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sort_compare(JSValue *a, JSValue *b, CompareArgs *arg)
|
static int32 sort_compare(JSValue *a, JSValue *b, CompareArgs *arg)
|
||||||
{
|
{
|
||||||
JSValue av = *(const JSValue *)a;
|
JSValue av = *(const JSValue *)a;
|
||||||
JSValue bv = *(const JSValue *)b;
|
JSValue bv = *(const JSValue *)b;
|
||||||
CompareArgs *ca = (CompareArgs *) arg;
|
CompareArgs *ca = (CompareArgs *) arg;
|
||||||
Context *cx = ca->context;
|
Context *cx = ca->context;
|
||||||
|
int32 result;
|
||||||
|
|
||||||
if (ca->target == NULL) {
|
if (ca->target == NULL) {
|
||||||
int32 result;
|
|
||||||
if (av.isUndefined() || bv.isUndefined()) {
|
if (av.isUndefined() || bv.isUndefined()) {
|
||||||
/* Put undefined properties at the end. */
|
/* Put undefined properties at the end. */
|
||||||
result = (av.isUndefined()) ? 1 : -1;
|
result = (av.isUndefined()) ? 1 : -1;
|
||||||
|
@ -496,8 +496,16 @@ static int sort_compare(JSValue *a, JSValue *b, CompareArgs *arg)
|
||||||
JSValue argv[2];
|
JSValue argv[2];
|
||||||
argv[0] = av;
|
argv[0] = av;
|
||||||
argv[1] = bv;
|
argv[1] = bv;
|
||||||
JSValue result = cx->invokeFunction(ca->target, kNullValue, argv, 2);
|
JSValue v = cx->invokeFunction(ca->target, kNullValue, argv, 2);
|
||||||
return (int32)(result.toInt32(cx).f64);
|
float64 f = v.toNumber(cx).f64;
|
||||||
|
if (JSDOUBLE_IS_NaN(f) || (f == 0))
|
||||||
|
result = 0;
|
||||||
|
else
|
||||||
|
if (f > 0)
|
||||||
|
result = 1;
|
||||||
|
else
|
||||||
|
result = -1;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -509,14 +517,15 @@ static JSValue Array_sort(Context *cx, const JSValue& thisValue, JSValue *argv,
|
||||||
|
|
||||||
CompareArgs ca;
|
CompareArgs ca;
|
||||||
ca.context = cx;
|
ca.context = cx;
|
||||||
|
ca.target = NULL;
|
||||||
|
|
||||||
if (argc > 0) {
|
if (argc > 0) {
|
||||||
if (!argv[0].isFunction())
|
if (!argv[0].isUndefined()) {
|
||||||
cx->reportError(Exception::typeError, "sort needs a compare function");
|
if (!argv[0].isFunction())
|
||||||
ca.target = argv[0].function;
|
cx->reportError(Exception::typeError, "sort needs a compare function");
|
||||||
|
ca.target = argv[0].function;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
ca.target = NULL;
|
|
||||||
|
|
||||||
JSObject *thisObj = thisValue.object;
|
JSObject *thisObj = thisValue.object;
|
||||||
thisObj->getProperty(cx, cx->Length_StringAtom, CURRENT_ATTR);
|
thisObj->getProperty(cx, cx->Length_StringAtom, CURRENT_ATTR);
|
||||||
|
|
|
@ -375,8 +375,10 @@ static JSValue Date_makeTime(Context *cx, const JSValue& thisValue, JSValue *arg
|
||||||
if (JSDOUBLE_IS_NaN(result))
|
if (JSDOUBLE_IS_NaN(result))
|
||||||
return kNaNValue;
|
return kNaNValue;
|
||||||
|
|
||||||
if (argc == 0)
|
if (argc == 0) {
|
||||||
argc = 1; /* should be safe, because length of all settors is 1 */
|
*date = nan;
|
||||||
|
return kNaNValue;
|
||||||
|
}
|
||||||
else if (argc > maxargs)
|
else if (argc > maxargs)
|
||||||
argc = maxargs; /* clamp argc */
|
argc = maxargs; /* clamp argc */
|
||||||
|
|
||||||
|
@ -439,8 +441,10 @@ static JSValue Date_makeDate(Context *cx, const JSValue& thisValue, JSValue *arg
|
||||||
result = *date;
|
result = *date;
|
||||||
|
|
||||||
/* see complaint about ECMA in date_MakeTime */
|
/* see complaint about ECMA in date_MakeTime */
|
||||||
if (argc == 0)
|
if (argc == 0) {
|
||||||
argc = 1; /* should be safe, because length of all settors is 1 */
|
*date = nan;
|
||||||
|
return kNaNValue;
|
||||||
|
}
|
||||||
else if (argc > maxargs)
|
else if (argc > maxargs)
|
||||||
argc = maxargs; /* clamp argc */
|
argc = maxargs; /* clamp argc */
|
||||||
|
|
||||||
|
|
|
@ -126,6 +126,7 @@ namespace JavaScript {
|
||||||
bool constant; // true for const variables and parameters
|
bool constant; // true for const variables and parameters
|
||||||
|
|
||||||
JS2Runtime::Property *prop; // the sematics/codegen passes stuff their data in here.
|
JS2Runtime::Property *prop; // the sematics/codegen passes stuff their data in here.
|
||||||
|
JS2Runtime::JSObject *scope; // ditto
|
||||||
|
|
||||||
VariableBinding(size_t pos, const StringAtom *name, ExprNode *type, ExprNode *initializer, bool constant):
|
VariableBinding(size_t pos, const StringAtom *name, ExprNode *type, ExprNode *initializer, bool constant):
|
||||||
ParseNode(pos), next(0), name(name), type(type), initializer(initializer), constant(constant) {}
|
ParseNode(pos), next(0), name(name), type(type), initializer(initializer), constant(constant) {}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче