зеркало из 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", },
|
||||
{ -1, "Pop", },
|
||||
{ -128, "PopN", },
|
||||
{ -1, "VoidPop", },
|
||||
{ 0, "GetField", },
|
||||
{ -1, "SetField", },
|
||||
{ 1, "GetMethod", },
|
||||
|
@ -729,7 +730,8 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3
|
|||
VariableBinding *v = vs->bindings;
|
||||
bool isStatic = (vs->attributeValue->mTrueFlags & Property::Static) == Property::Static;
|
||||
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
|
||||
if (v->initializer) {
|
||||
if (isStatic && (static_cg != NULL)) {
|
||||
|
@ -903,7 +905,7 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3
|
|||
NOT_REACHED("what else??");
|
||||
}
|
||||
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);
|
||||
addOp(GetPropertyOp);
|
||||
addStringRef(m_cx->Value_StringAtom);
|
||||
|
@ -925,7 +927,7 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3
|
|||
addLong(1);
|
||||
addByte(Explicit);
|
||||
iteratorWriteRef->emitCodeSequence(this);
|
||||
addOp(PopOp);
|
||||
addOp(VoidPopOp);
|
||||
|
||||
setLabel(labelAtTestCondition);
|
||||
iteratorReadRef->emitCodeSequence(this);
|
||||
|
@ -948,16 +950,7 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3
|
|||
addOp(PopOp);
|
||||
|
||||
setLabel(labelAtEnd);
|
||||
/*
|
||||
if (valueBaseDepth) {
|
||||
if (valueBaseDepth > 1) {
|
||||
addOpAdjustDepth(PopNOp, -valueBaseDepth);
|
||||
addShort(valueBaseDepth);
|
||||
}
|
||||
else
|
||||
addOp(PopOp);
|
||||
}
|
||||
*/
|
||||
|
||||
delete objectReadRef;
|
||||
delete objectWriteRef;
|
||||
delete iteratorReadRef;
|
||||
|
@ -2366,6 +2359,9 @@ BinaryOpEquals:
|
|||
return Object_Type;
|
||||
}
|
||||
break;
|
||||
case ExprNode::regExp:
|
||||
m_cx->reportError(Exception::internalError, "Regular expressions nyi", p->pos);
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED("Not Implemented Yet");
|
||||
}
|
||||
|
@ -2409,6 +2405,7 @@ uint32 printInstruction(Formatter &f, uint32 i, const ByteCodeModule& bcm)
|
|||
case DupOp:
|
||||
case DupInsertOp:
|
||||
case PopOp:
|
||||
case VoidPopOp:
|
||||
case LoadGlobalObjectOp:
|
||||
case NewClosureOp:
|
||||
case ClassOp:
|
||||
|
|
|
@ -121,6 +121,7 @@ typedef enum {
|
|||
DupInsertNOp, // <N> <N things> <object2> --> <object2> <N things> <object2>
|
||||
PopOp, // <object> -->
|
||||
PopNOp, // <N> <N things> -->
|
||||
VoidPopOp, // <object>--> (doesn't cache result value)
|
||||
// for instance members
|
||||
GetFieldOp, // <slot> <base> --> <object>
|
||||
SetFieldOp, // <slot> <base> <object> --> <object>
|
||||
|
|
|
@ -51,6 +51,7 @@ static const char *const kindStrings[] = {
|
|||
"Type error", // Yype error
|
||||
"Uncaught exception error", // uncaught exception error
|
||||
"Semantic error", // semantic error
|
||||
"User exception", // 'throw' from user code
|
||||
};
|
||||
|
||||
// Return a null-terminated string describing the exception's kind.
|
||||
|
|
|
@ -55,7 +55,8 @@ namespace JavaScript
|
|||
rangeError,
|
||||
typeError,
|
||||
uncaughtError,
|
||||
semanticError
|
||||
semanticError,
|
||||
userException
|
||||
};
|
||||
|
||||
Kind kind; // The exception's kind
|
||||
|
|
|
@ -63,12 +63,6 @@ namespace JavaScript {
|
|||
namespace JS2Runtime {
|
||||
|
||||
|
||||
class JSException {
|
||||
public:
|
||||
};
|
||||
|
||||
|
||||
|
||||
inline char narrow(char16 ch) { return char(ch); }
|
||||
|
||||
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;
|
||||
Parser p(mWorld, a, mFlags, str, fileName);
|
||||
Reader *oldReader = mReader;
|
||||
mReader = &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);
|
||||
setReader(&p.lexer.reader);
|
||||
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) {
|
||||
setReader(NULL);
|
||||
bcm->setSource(str, fileName);
|
||||
|
@ -103,10 +97,11 @@ JSValue Context::readEvalString(const String &str, const String& fileName, Scope
|
|||
delete bcm;
|
||||
}
|
||||
}
|
||||
catch (JSException *x) {
|
||||
catch (Exception &x) {
|
||||
setReader(oldReader);
|
||||
throw x;
|
||||
}
|
||||
setReader(oldReader);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -220,7 +215,7 @@ JSValue Context::interpret(JS2Runtime::ByteCodeModule *bcm, int offset, ScopeCha
|
|||
try {
|
||||
result = interpret(pc, endPC);
|
||||
}
|
||||
catch (JSException *x) {
|
||||
catch (Exception &x) {
|
||||
Activation *prev = mActivationStack.top();
|
||||
mActivationStack.pop();
|
||||
|
||||
|
@ -420,7 +415,12 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
|||
switch ((ByteCodeOp)(*pc++)) {
|
||||
case PopOp:
|
||||
{
|
||||
result = popValue(); // XXX debug only? - just decrement top
|
||||
result = popValue();
|
||||
}
|
||||
break;
|
||||
case VoidPopOp:
|
||||
{
|
||||
popValue(); // XXX just decrement top
|
||||
}
|
||||
break;
|
||||
case PopNOp:
|
||||
|
@ -627,22 +627,18 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
|||
if (target->isPrototype() && mThis.isNull())
|
||||
mThis = JSValue(getGlobalObject());
|
||||
|
||||
JSValue *argBase = getBase(stackSize() - argCount);
|
||||
|
||||
if (!target->isNative()) {
|
||||
|
||||
JSValue *argBase = buildArgumentBlock(target, argCount);
|
||||
// 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.
|
||||
|
||||
argBase = buildArgumentBlock(target, argCount);
|
||||
|
||||
mActivationStack.push(new Activation(mLocals, mStack, mStackTop - (cleanUp + 1),
|
||||
mScopeChain,
|
||||
mArgumentBase, oldThis,
|
||||
pc, mCurModule));
|
||||
mScopeChain = target->getScopeChain();
|
||||
// if (mThis.isObject())
|
||||
// mScopeChain->addScope(mThis.object);
|
||||
mScopeChain->addScope(target->getParameterBarrel());
|
||||
mScopeChain->addScope(target->getActivation());
|
||||
|
||||
if (!target->isChecked()) {
|
||||
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->addScope(target->getParameterBarrel());
|
||||
mScopeChain->addScope(target->getActivation());
|
||||
|
||||
mCurModule = target->getByteCode();
|
||||
pc = mCurModule->mCodeBase;
|
||||
endPC = mCurModule->mCodeBase + mCurModule->mLength;
|
||||
|
@ -664,6 +657,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
|||
mStackTop = 0;
|
||||
}
|
||||
else {
|
||||
JSValue *argBase = getBase(stackSize() - argCount);
|
||||
// native functions may still need access to information
|
||||
// about the currently executing function.
|
||||
mActivationStack.push(new Activation(mLocals, mStack, mStackTop - (cleanUp + 1),
|
||||
|
@ -790,10 +784,10 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
|||
uint32 index = *((uint32 *)pc);
|
||||
pc += sizeof(uint32);
|
||||
const String &name = *mCurModule->getString(index);
|
||||
PropertyIterator it;
|
||||
if (mScopeChain->hasOwnProperty(name, CURRENT_ATTR, Read, &it))
|
||||
mScopeChain->deleteProperty(name, CURRENT_ATTR);
|
||||
pushValue(kTrueValue);
|
||||
if (mScopeChain->deleteName(this, name, CURRENT_ATTR))
|
||||
pushValue(kTrueValue);
|
||||
else
|
||||
pushValue(kFalseValue);
|
||||
}
|
||||
break;
|
||||
case DeleteOp:
|
||||
|
@ -907,8 +901,18 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
|||
else
|
||||
reportError(Exception::typeError, "InstanceOf couldn't find [[hasInstance]]");
|
||||
}
|
||||
else
|
||||
reportError(Exception::typeError, "InstanceOf needs function object");
|
||||
else {
|
||||
// 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;
|
||||
case GetNameOp:
|
||||
|
@ -994,7 +998,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
|||
try {
|
||||
result = interpret(target->getByteCode(), 0, target->getScopeChain(), argBase[0], argBase, argCount);
|
||||
}
|
||||
catch (JSException *x) {
|
||||
catch (Exception &x) {
|
||||
delete[] argBase;
|
||||
throw x;
|
||||
}
|
||||
|
@ -1050,7 +1054,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
|||
try {
|
||||
result = interpret(target->getByteCode(), 0, target->getScopeChain(), *baseValue, argBase, argCount);
|
||||
}
|
||||
catch (JSException *x) {
|
||||
catch (Exception &x) {
|
||||
delete[] argBase;
|
||||
throw x;
|
||||
}
|
||||
|
@ -1105,7 +1109,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
|||
try {
|
||||
result = interpret(target->getByteCode(), 0, target->getScopeChain(), kNullValue, argBase, argCount);
|
||||
}
|
||||
catch (JSException *x) {
|
||||
catch (Exception &x) {
|
||||
delete[] argBase;
|
||||
throw x;
|
||||
}
|
||||
|
@ -1341,12 +1345,12 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
|||
JSArrayInstance *args = (JSArrayInstance *)Array_Type->newInstance(this);
|
||||
for (uint32 i = 0; i < argCount; 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 {
|
||||
result = interpret(target->getByteCode(), 0, target->getScopeChain(), newThis, argBase, argCount);
|
||||
}
|
||||
catch (JSException *x) {
|
||||
catch (Exception &x) {
|
||||
delete[] argBase;
|
||||
throw x;
|
||||
}
|
||||
|
@ -1553,41 +1557,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
|||
break;
|
||||
case ThrowOp:
|
||||
{
|
||||
throw new JSException();
|
||||
/*
|
||||
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");
|
||||
*/
|
||||
throw Exception(Exception::userException, "");
|
||||
}
|
||||
break;
|
||||
case ClassOp:
|
||||
|
@ -1651,11 +1621,38 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
|||
reportError(Exception::internalError, "Bad Opcode");
|
||||
}
|
||||
}
|
||||
catch (JSException *jsx) {
|
||||
JSValue x = topValue();
|
||||
catch (Exception &jsx) {
|
||||
if (mTryStack.size() > 0) {
|
||||
HandlerData *hndlr = (HandlerData *)mTryStack.top();
|
||||
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) {
|
||||
ASSERT(mActivationStack.size() > 0);
|
||||
Activation *prev;// = mActivationStack.top();
|
||||
|
@ -1673,7 +1670,6 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
|||
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;
|
||||
|
@ -1684,10 +1680,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
|
|||
pushValue(x);
|
||||
}
|
||||
else
|
||||
reportError(Exception::uncaughtError, "No handler for throw");
|
||||
}
|
||||
catch (Exception x) {
|
||||
throw x;
|
||||
throw jsx; //reportError(Exception::uncaughtError, "No handler for throw");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -2259,7 +2252,7 @@ JSValue JSValue::valueToNumber(Context *cx, const JSValue& value)
|
|||
return JSValue(stringToNumber(value.string));
|
||||
case object_tag:
|
||||
case function_tag:
|
||||
return value.toPrimitive(cx, NoHint).toNumber(cx);
|
||||
return value.toPrimitive(cx, NumberHint).toNumber(cx);
|
||||
case boolean_tag:
|
||||
return JSValue((value.boolean) ? 1.0 : 0.0);
|
||||
case undefined_tag:
|
||||
|
@ -2326,7 +2319,7 @@ JSValue JSValue::valueToString(Context *cx, const JSValue& value)
|
|||
}
|
||||
if (target)
|
||||
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
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -81,6 +81,13 @@ JSType *Attribute_Type;
|
|||
JSType *NamedArgument_Type;
|
||||
JSArrayType *Array_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)
|
||||
|
@ -672,6 +679,18 @@ void ScopeChain::setNameValue(Context *cx, const String& name, AttributeStmtNode
|
|||
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); }
|
||||
|
||||
JSObject *ScopeChain::getNameValue(Context *cx, const String& name, AttributeStmtNode *attr)
|
||||
|
@ -989,8 +1008,8 @@ void ScopeChain::collectNames(StmtNode *p)
|
|||
}
|
||||
}
|
||||
break;
|
||||
case StmtNode::If:
|
||||
case StmtNode::With:
|
||||
case StmtNode::If:
|
||||
case StmtNode::DoWhile:
|
||||
case StmtNode::While:
|
||||
{
|
||||
|
@ -1008,13 +1027,16 @@ void ScopeChain::collectNames(StmtNode *p)
|
|||
case StmtNode::Try:
|
||||
{
|
||||
TryStmtNode *t = checked_cast<TryStmtNode *>(p);
|
||||
collectNames(t->stmt);
|
||||
if (t->catches) {
|
||||
CatchClause *c = t->catches;
|
||||
while (c) {
|
||||
collectNames(c->stmt);
|
||||
c->prop = defineVariable(m_cx, c->name, NULL, NULL);
|
||||
c = c->next;
|
||||
}
|
||||
}
|
||||
if (t->finally) collectNames(t->finally);
|
||||
}
|
||||
break;
|
||||
case StmtNode::For:
|
||||
|
@ -1046,6 +1068,7 @@ void ScopeChain::collectNames(StmtNode *p)
|
|||
v->prop = defineStaticVariable(m_cx, *v->name, vs, NULL);
|
||||
else
|
||||
v->prop = defineVariable(m_cx, *v->name, vs, NULL);
|
||||
v->scope = mScopeStack.back();
|
||||
v = v->next;
|
||||
}
|
||||
}
|
||||
|
@ -1590,17 +1613,20 @@ void Context::buildRuntimeForStmt(StmtNode *p)
|
|||
case StmtNode::Try:
|
||||
{
|
||||
TryStmtNode *t = checked_cast<TryStmtNode *>(p);
|
||||
buildRuntimeForStmt(t->stmt);
|
||||
if (t->catches) {
|
||||
CatchClause *c = t->catches;
|
||||
while (c) {
|
||||
buildRuntimeForStmt(c->stmt);
|
||||
c->prop->mType = mScopeChain->extractType(c->type);
|
||||
c = c->next;
|
||||
}
|
||||
}
|
||||
if (t->finally) buildRuntimeForStmt(t->finally);
|
||||
}
|
||||
break;
|
||||
case StmtNode::If:
|
||||
case StmtNode::With:
|
||||
case StmtNode::If:
|
||||
case StmtNode::DoWhile:
|
||||
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
|
||||
|
||||
if (argc != 0) {
|
||||
if (argv[0].isObject())
|
||||
if (argv[0].isObject() || argv[0].isFunction() || argv[0].isType())
|
||||
thatValue = argv[0];
|
||||
else
|
||||
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;
|
||||
}
|
||||
|
||||
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*/)
|
||||
{
|
||||
ASSERT(thisValue.isObject());
|
||||
|
@ -2054,6 +2088,76 @@ static JSValue Boolean_valueOf(Context *cx, const JSValue& thisValue, JSValue *
|
|||
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)
|
||||
{
|
||||
ASSERT(argc == 1);
|
||||
|
@ -2065,15 +2169,18 @@ static JSValue ExtendAttribute_Invoke(Context * /*cx*/, const JSValue& /*thisVal
|
|||
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())
|
||||
return argv[0];
|
||||
const String *sourceStr = argv[0].toString(cx).string;
|
||||
if (argc > 0) {
|
||||
if (!argv[0].isString())
|
||||
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)
|
||||
|
@ -2125,6 +2232,149 @@ static JSValue GlobalObject_isFinite(Context *cx, const JSValue& /*thisValue*/,
|
|||
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)
|
||||
: JSObject(Function_Type),
|
||||
|
@ -2276,20 +2526,27 @@ void Context::initBuiltins()
|
|||
{
|
||||
ClassDef builtInClasses[] =
|
||||
{
|
||||
{ "Object", Object_Constructor, &kUndefinedValue },
|
||||
{ "Type", NULL, &kNullValue },
|
||||
{ "Function", Function_Constructor, &kNullValue },
|
||||
{ "Number", Number_Constructor, &kPositiveZero },
|
||||
{ "Integer", Integer_Constructor, &kPositiveZero },
|
||||
{ "String", String_Constructor, &kNullValue },
|
||||
{ "Array", Array_Constructor, &kNullValue },
|
||||
{ "Boolean", Boolean_Constructor, &kFalseValue },
|
||||
{ "Void", NULL, &kUndefinedValue },
|
||||
{ "Unit", NULL, &kNullValue },
|
||||
{ "Attribute", NULL, &kNullValue },
|
||||
{ "NamedArgument", NULL, &kNullValue },
|
||||
{ "Date", Date_Constructor, &kPositiveZero },
|
||||
{ "Null", NULL, &kNullValue },
|
||||
{ "Object", Object_Constructor, &kUndefinedValue },
|
||||
{ "Type", NULL, &kNullValue },
|
||||
{ "Function", Function_Constructor, &kNullValue },
|
||||
{ "Number", Number_Constructor, &kPositiveZero },
|
||||
{ "Integer", Integer_Constructor, &kPositiveZero },
|
||||
{ "String", String_Constructor, &kNullValue },
|
||||
{ "Array", Array_Constructor, &kNullValue },
|
||||
{ "Boolean", Boolean_Constructor, &kFalseValue },
|
||||
{ "Void", NULL, &kUndefinedValue },
|
||||
{ "Unit", NULL, &kNullValue },
|
||||
{ "Attribute", NULL, &kNullValue },
|
||||
{ "NamedArgument", NULL, &kNullValue },
|
||||
{ "Date", Date_Constructor, &kPositiveZero },
|
||||
{ "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);
|
||||
|
@ -2334,6 +2591,13 @@ void Context::initBuiltins()
|
|||
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);
|
||||
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)));
|
||||
|
||||
|
@ -2374,6 +2638,12 @@ void Context::initBuiltins()
|
|||
{ "valueOf", Number_Type, 0, Boolean_valueOf },
|
||||
{ NULL }
|
||||
};
|
||||
ProtoFunDef errorProtos[] =
|
||||
{
|
||||
{ "toString", String_Type, 0, Error_toString },
|
||||
{ "toSource", String_Type, 0, Error_toString },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
ASSERT(mGlobal);
|
||||
*mGlobal = Object_Type->newInstance(this);
|
||||
|
@ -2392,9 +2662,17 @@ void Context::initBuiltins()
|
|||
initClass(NamedArgument_Type, &builtInClasses[11], NULL);
|
||||
initClass(Date_Type, &builtInClasses[12], getDateProtos() );
|
||||
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));
|
||||
|
||||
|
||||
Object_Type->mTypeCast = new JSFunction(this, Object_Constructor, Object_Type);
|
||||
Function_Type->mTypeCast = new JSFunction(this, Function_Constructor, Object_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->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->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));
|
||||
|
||||
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"]),
|
||||
Empty_StringAtom (world.identifiers[""]),
|
||||
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),
|
||||
mScopeChain(NULL),
|
||||
|
@ -2596,6 +2887,8 @@ Context::Context(JSObject **global, World &world, Arena &a, Pragma::Flags flags)
|
|||
{ "parseFloat", Number_Type, 2, GlobalObject_ParseFloat },
|
||||
{ "isNaN", Boolean_Type, 2, GlobalObject_isNaN },
|
||||
{ "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++) {
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
/*
|
||||
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, NaN_StringAtom, (NamespaceList *)(NULL), Property::NoAttribute, Void_Type, kNaNValue);
|
||||
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);
|
||||
}
|
||||
|
||||
bool deleteName(Context *cx, const String& name, AttributeStmtNode *attr);
|
||||
/*
|
||||
bool hasOwnProperty(const String& name, NamespaceList *names, Access acc, PropertyIterator *p)
|
||||
{
|
||||
JSObject *top = mScopeStack.back();
|
||||
return top->hasOwnProperty(name, names, acc, p);
|
||||
}
|
||||
|
||||
*/
|
||||
// delete a property from the top object (already know it's there)
|
||||
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 {
|
||||
public:
|
||||
|
@ -1444,6 +1456,15 @@ XXX ...couldn't get this to work...
|
|||
StringAtom& Infinity_StringAtom;
|
||||
StringAtom& Empty_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 initClass(JSType *type, ClassDef *cdef, PrototypeFunctions *pdef);
|
||||
|
@ -1580,6 +1601,10 @@ XXX ...couldn't get this to work...
|
|||
|
||||
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 readEvalString(const String &str, const String& fileName, ScopeChain *scopeChain, const JSValue& thisValue);
|
||||
|
|
|
@ -407,7 +407,7 @@ typedef struct QSortArgs {
|
|||
CompareArgs *arg;
|
||||
} QSortArgs;
|
||||
|
||||
static int sort_compare(JSValue *a, JSValue *b, CompareArgs *arg);
|
||||
static int32 sort_compare(JSValue *a, JSValue *b, CompareArgs *arg);
|
||||
|
||||
static void
|
||||
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);
|
||||
}
|
||||
|
||||
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 bv = *(const JSValue *)b;
|
||||
CompareArgs *ca = (CompareArgs *) arg;
|
||||
Context *cx = ca->context;
|
||||
int32 result;
|
||||
|
||||
if (ca->target == NULL) {
|
||||
int32 result;
|
||||
if (av.isUndefined() || bv.isUndefined()) {
|
||||
/* Put undefined properties at the end. */
|
||||
result = (av.isUndefined()) ? 1 : -1;
|
||||
|
@ -496,8 +496,16 @@ static int sort_compare(JSValue *a, JSValue *b, CompareArgs *arg)
|
|||
JSValue argv[2];
|
||||
argv[0] = av;
|
||||
argv[1] = bv;
|
||||
JSValue result = cx->invokeFunction(ca->target, kNullValue, argv, 2);
|
||||
return (int32)(result.toInt32(cx).f64);
|
||||
JSValue v = cx->invokeFunction(ca->target, kNullValue, argv, 2);
|
||||
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;
|
||||
ca.context = cx;
|
||||
ca.target = NULL;
|
||||
|
||||
if (argc > 0) {
|
||||
if (!argv[0].isFunction())
|
||||
cx->reportError(Exception::typeError, "sort needs a compare function");
|
||||
ca.target = argv[0].function;
|
||||
if (!argv[0].isUndefined()) {
|
||||
if (!argv[0].isFunction())
|
||||
cx->reportError(Exception::typeError, "sort needs a compare function");
|
||||
ca.target = argv[0].function;
|
||||
}
|
||||
}
|
||||
else
|
||||
ca.target = NULL;
|
||||
|
||||
JSObject *thisObj = thisValue.object;
|
||||
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))
|
||||
return kNaNValue;
|
||||
|
||||
if (argc == 0)
|
||||
argc = 1; /* should be safe, because length of all settors is 1 */
|
||||
if (argc == 0) {
|
||||
*date = nan;
|
||||
return kNaNValue;
|
||||
}
|
||||
else if (argc > maxargs)
|
||||
argc = maxargs; /* clamp argc */
|
||||
|
||||
|
@ -439,8 +441,10 @@ static JSValue Date_makeDate(Context *cx, const JSValue& thisValue, JSValue *arg
|
|||
result = *date;
|
||||
|
||||
/* see complaint about ECMA in date_MakeTime */
|
||||
if (argc == 0)
|
||||
argc = 1; /* should be safe, because length of all settors is 1 */
|
||||
if (argc == 0) {
|
||||
*date = nan;
|
||||
return kNaNValue;
|
||||
}
|
||||
else if (argc > maxargs)
|
||||
argc = maxargs; /* clamp argc */
|
||||
|
||||
|
|
|
@ -126,6 +126,7 @@ namespace JavaScript {
|
|||
bool constant; // true for const variables and parameters
|
||||
|
||||
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):
|
||||
ParseNode(pos), next(0), name(name), type(type), initializer(initializer), constant(constant) {}
|
||||
|
|
Загрузка…
Ссылка в новой задаче