Snapshot of latest fixes for expression/statement/date/boolean/types ECMA

test suite related bug fixing.
This commit is contained in:
rogerl%netscape.com 2001-09-28 01:16:52 +00:00
Родитель 2c954b679c
Коммит f1acd9f856
10 изменённых файлов: 491 добавлений и 331 удалений

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

@ -105,6 +105,13 @@ void StaticFieldReference::emitImplicitLoad(ByteCodeGen *bcg)
bcg->addPointer(mClass);
}
void StaticFieldReference::emitDelete(ByteCodeGen *bcg)
{
bcg->addOp(DeleteOp);
bcg->addStringRef(mName);
}
void FieldReference::emitImplicitLoad(ByteCodeGen *bcg)
{
@ -323,6 +330,7 @@ ByteCodeData gByteCodeData[OpCodeCount] = {
{ -128, "DupN", },
{ -128, "DupInsertN", },
{ -1, "Pop", },
{ -128, "PopN", },
{ 0, "GetField", },
{ -1, "SetField", },
{ 1, "GetMethod", },
@ -412,7 +420,7 @@ uint32 ByteCodeGen::getLabel(LabelStmtNode *lbl)
return result;
}
uint32 ByteCodeGen::getTopLabel(Label::LabelKind kind, const StringAtom *name)
uint32 ByteCodeGen::getTopLabel(Label::LabelKind kind, const StringAtom *name, StmtNode *p)
{
uint32 result = uint32(-1);
for (std::vector<uint32>::reverse_iterator i = mLabelStack.rbegin(),
@ -426,11 +434,11 @@ uint32 ByteCodeGen::getTopLabel(Label::LabelKind kind, const StringAtom *name)
if (mLabelList[*i].matches(name))
return result;
}
NOT_REACHED("label not found");
m_cx->reportError(Exception::syntaxError, "label not found", p->pos);
return false;
}
uint32 ByteCodeGen::getTopLabel(Label::LabelKind kind)
uint32 ByteCodeGen::getTopLabel(Label::LabelKind kind, StmtNode *p)
{
for (std::vector<uint32>::reverse_iterator i = mLabelStack.rbegin(),
end = mLabelStack.rend();
@ -439,7 +447,7 @@ uint32 ByteCodeGen::getTopLabel(Label::LabelKind kind)
if (mLabelList[*i].matches(kind))
return *i;
}
NOT_REACHED("label not found");
m_cx->reportError(Exception::syntaxError, "label not found", p->pos);
return false;
}
@ -615,7 +623,9 @@ void ByteCodeGen::genCodeForFunction(FunctionDefinition &f, size_t pos, JSFuncti
}
}
bool hasReturn = genCodeForStatement(f.body, NULL, NotALabel);
bool hasReturn = false;
if (f.body)
hasReturn = genCodeForStatement(f.body, NULL, NotALabel);
/*
// OPT - see above
@ -702,7 +712,7 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3
if (static_cg.hasContent()) {
// build a function to be invoked
// when the class is loaded
f = new JSFunction(Void_Type, mScopeChain);
f = new JSFunction(m_cx, Void_Type, mScopeChain);
ByteCodeModule *bcm = new ByteCodeModule(&static_cg, NULL);
if (m_cx->mReader)
bcm->setSource(m_cx->mReader->source, m_cx->mReader->sourceLocation);
@ -712,7 +722,7 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3
f = NULL;
if (bcg.hasContent()) {
// execute this function now to form the initial instance
f = new JSFunction(Void_Type, mScopeChain);
f = new JSFunction(m_cx, Void_Type, mScopeChain);
ByteCodeModule *bcm = new ByteCodeModule(&bcg, NULL);
if (m_cx->mReader)
bcm->setSource(m_cx->mReader->source, m_cx->mReader->sourceLocation);
@ -857,6 +867,11 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3
else
NOT_REACHED("what else??");
}
if (value == NULL)
m_cx->reportError(Exception::referenceError, "Invalid for..in target");
uint16 valueBaseDepth = value->baseExpressionDepth();
uint32 breakLabel = getLabel(Label::BreakLabel);
uint32 labelAtTopOfBlock = getLabel();
uint32 labelAtIncrement = getLabel(Label::ContinueLabel);
@ -902,6 +917,14 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3
addFixup(labelAtTestCondition);
setLabel(labelAtTopOfBlock);
if (valueBaseDepth) {
if (valueBaseDepth > 1) {
addOpAdjustDepth(DupNOp, valueBaseDepth);
addShort(valueBaseDepth);
}
else
addOp(DupOp);
}
iteratorReadRef->emitCodeSequence(this);
addOp(GetPropertyOp);
addStringRef(m_cx->Value_StringAtom);
@ -946,6 +969,14 @@ 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;
@ -987,6 +1018,10 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3
addOp(JumpTrueOp);
addFixup(labelAtTopOfBlock);
}
else {
addOp(JumpOp);
addFixup(labelAtTopOfBlock);
}
setLabel(breakLabel);
}
@ -1009,9 +1044,9 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3
GoStmtNode *g = checked_cast<GoStmtNode *>(p);
addOp(JumpOp);
if (g->name)
addFixup(getTopLabel(Label::BreakLabel, g->name));
addFixup(getTopLabel(Label::BreakLabel, g->name, p));
else
addFixup(getTopLabel(Label::BreakLabel));
addFixup(getTopLabel(Label::BreakLabel, p));
}
break;
case StmtNode::Continue:
@ -1019,9 +1054,9 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3
GoStmtNode *g = checked_cast<GoStmtNode *>(p);
addOp(JumpOp);
if (g->name)
addFixup(getTopLabel(Label::ContinueLabel, g->name));
addFixup(getTopLabel(Label::ContinueLabel, g->name, p));
else
addFixup(getTopLabel(Label::ContinueLabel));
addFixup(getTopLabel(Label::ContinueLabel, p));
}
break;
case StmtNode::Switch:
@ -1673,7 +1708,7 @@ PreXcrement:
uint16 baseDepth = readRef->baseExpressionDepth();
if (baseDepth) { // duplicate the base expression
if (baseDepth > 1) {
addOpAdjustDepth(DupNOp, -baseDepth);
addOpAdjustDepth(DupNOp, baseDepth);
addShort(baseDepth);
}
else
@ -1785,7 +1820,7 @@ BinaryOpEquals:
uint16 baseDepth = readRef->baseExpressionDepth();
if (baseDepth) { // duplicate the base expression
if (baseDepth > 1) {
addOp(DupNOp);
addOpAdjustDepth(DupNOp, baseDepth);
addShort(baseDepth);
}
else
@ -1821,7 +1856,7 @@ BinaryOpEquals:
uint16 baseDepth = readRef->baseExpressionDepth();
if (baseDepth) { // duplicate the base expression
if (baseDepth > 1) {
addOpAdjustDepth(DupNOp, -baseDepth);
addOpAdjustDepth(DupNOp, baseDepth);
addShort(baseDepth);
}
else
@ -1862,7 +1897,7 @@ BinaryOpEquals:
uint16 baseDepth = readRef->baseExpressionDepth();
if (baseDepth) { // duplicate the base expression
if (baseDepth > 1) {
addOpAdjustDepth(DupNOp, -baseDepth);
addOpAdjustDepth(DupNOp, baseDepth);
addShort(baseDepth);
}
else
@ -1903,7 +1938,7 @@ BinaryOpEquals:
uint16 baseDepth = readRef->baseExpressionDepth();
if (baseDepth) { // duplicate the base expression
if (baseDepth > 1) {
addOpAdjustDepth(DupNOp, -baseDepth);
addOpAdjustDepth(DupNOp, baseDepth);
addShort(baseDepth);
}
else
@ -2175,7 +2210,7 @@ BinaryOpEquals:
{
addOp(LoadTypeOp);
addPointer(Array_Type);
addOpAdjustDepth(NewInstanceOp, 1);
addOpAdjustDepth(NewInstanceOp, 0);
addLong(0);
PairListExprNode *plen = checked_cast<PairListExprNode *>(p);
ExprPairList *e = plen->pairs;
@ -2243,7 +2278,7 @@ BinaryOpEquals:
case ExprNode::functionLiteral:
{
FunctionExprNode *f = checked_cast<FunctionExprNode *>(p);
JSFunction *fnc = new JSFunction(NULL, mScopeChain);
JSFunction *fnc = new JSFunction(m_cx, NULL, mScopeChain);
uint32 reqArgCount = 0;
uint32 optArgCount = 0;
@ -2257,7 +2292,7 @@ BinaryOpEquals:
optArgCount++;
b = b->next;
}
fnc->setArgCounts(reqArgCount, optArgCount, (f->function.restParameter != NULL));
fnc->setArgCounts(m_cx, reqArgCount, optArgCount, (f->function.restParameter != NULL));
if (mScopeChain->isPossibleUncheckedFunction(&f->function))
fnc->setIsPrototype(true);
@ -2324,6 +2359,7 @@ BinaryOpEquals:
{
BinaryExprNode *c = checked_cast<BinaryExprNode *>(p);
genExpr(c->op1);
addOp(PopOp);
return genExpr(c->op2);
}
break;
@ -2403,6 +2439,7 @@ uint32 printInstruction(Formatter &f, uint32 i, const ByteCodeModule& bcm)
break;
case DupNOp:
case PopNOp:
case DupInsertNOp:
{
uint16 u = bcm.getShort(i);

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

@ -117,9 +117,10 @@ typedef enum {
SwapOp, // <object1> <object2> --> <object2> <object1>
DupOp, // <object> --> <object> <object>
DupInsertOp, // <object1> <object2> --> <object2> <object1> <object2>
DupNOp, // <N> <object> --> <object> { N times }
DupInsertNOp, // <N> <object> {xN} <object2> --> <object2> <object> {xN} <object2>
DupNOp, // <N> <N things> --> <N things> <N things>
DupInsertNOp, // <N> <N things> <object2> --> <object2> <N things> <object2>
PopOp, // <object> -->
PopNOp, // <N> <N things> -->
// for instance members
GetFieldOp, // <slot> <base> --> <object>
SetFieldOp, // <slot> <base> <object> --> <object>
@ -365,9 +366,9 @@ extern ByteCodeData gByteCodeData[OpCodeCount];
uint32 getLabel(LabelStmtNode *lbl);
uint32 getTopLabel(Label::LabelKind kind, const StringAtom *name);
uint32 getTopLabel(Label::LabelKind kind, const StringAtom *name, StmtNode *p);
uint32 getTopLabel(Label::LabelKind kind);
uint32 getTopLabel(Label::LabelKind kind, StmtNode *p);
void setLabel(uint32 label)
{

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

@ -73,6 +73,7 @@ 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));
@ -88,7 +89,6 @@ JSValue Context::readEvalString(const String &str, const String& fileName, Scope
f.end();
stdOut << '\n';
}
buildRuntime(parsedStatements);
JS2Runtime::ByteCodeModule* bcm = genCode(parsedStatements, fileName);
if (bcm) {
@ -97,6 +97,7 @@ JSValue Context::readEvalString(const String &str, const String& fileName, Scope
result = interpret(bcm, 0, scopeChain, thisValue, NULL, 0);
delete bcm;
}
setReader(oldReader);
return result;
}
@ -384,6 +385,13 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
result = popValue(); // XXX debug only? - just decrement top
}
break;
case PopNOp:
{
uint16 count = *((uint16 *)pc);
pc += sizeof(uint16);
resizeStack(mStackTop - count);
}
break;
case DupOp:
{
JSValue v = topValue();
@ -401,14 +409,14 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
break;
case DupNOp:
{
JSValue v = topValue();
uint16 count = *((uint16 *)pc);
pc += sizeof(uint16);
JSValue *vp = getBase(stackSize() - count);
while (count--)
pushValue(v);
pushValue(*vp++);
}
break;
// <object> {xN} <object2> --> <object2> <object> {xN} <object2>
// <N things> <object2> --> <object2> <N things> <object2>
case DupInsertNOp:
{
JSValue v2 = topValue();
@ -550,16 +558,19 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
// XXX Note that this is different behaviour from JS1.5, where
// (e.g.) Array(2) is an invocation of the constructor.
if ((argCount > 1) || ((callFlags & ThisFlags) != NoThis))
reportError(Exception::referenceError, "Type cast can only take one argument");
JSValue v;
if (argCount > 0)
v = popValue();
popValue(); // don't need the target anymore
pushValue(mapValueToType(v, targetValue->type));
mThis = oldThis;
break; // all done
target = targetValue->type->getTypeCastFunction();
if (target == NULL) {
if ((argCount > 1) || ((callFlags & ThisFlags) != NoThis))
reportError(Exception::referenceError, "Type cast can only take one argument");
JSValue v;
if (argCount > 0)
v = popValue();
popValue(); // don't need the target anymore
pushValue(mapValueToType(v, targetValue->type));
mThis = oldThis;
break; // all done
}
}
}
else
@ -655,6 +666,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
mArgumentBase = prev->mArgumentBase;
mThis = prev->mThis;
mScopeChain = prev->mScopeChain;
pushValue(kUndefinedValue);
delete prev;
}
break;
@ -854,7 +866,17 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
uint32 index = *((uint32 *)pc);
pc += sizeof(uint32);
const String &name = *mCurModule->getString(index);
mScopeChain->getNameValue(this, name, CURRENT_ATTR);
JSObject *parent = mScopeChain->getNameValue(this, name, CURRENT_ATTR);
JSValue result = topValue();
if (result.isFunction() && result.function->isMethod()) {
popValue();
if (result.function->isConstructor())
// A constructor has to be called with a NULL 'this' in order to prompt it
// to construct the instance object.
pushValue(JSValue((JSFunction *)(new JSBoundFunction(result.function, NULL))));
else
pushValue(JSValue((JSFunction *)(new JSBoundFunction(result.function, parent))));
}
}
break;
case GetTypeOfNameOp:
@ -887,13 +909,13 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
// Use the type of the base to dispatch on...
JSObject *obj = NULL;
if (baseValue->isType())
obj = baseValue->type;
else
if (baseValue->isFunction())
obj = baseValue->function;
else
if (baseValue->isObject())
if (baseValue->isType())
obj = baseValue->type;
else
if (baseValue->isFunction())
obj = baseValue->function;
else
if (baseValue->isObject())
obj = baseValue->object;
else
obj = baseValue->toObject(this).object;
@ -1040,10 +1062,10 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
mPC = pc;
const String &name = *mCurModule->getString(index);
obj->getProperty(this, name, CURRENT_ATTR);
// if the result is a function of some kind, bind
// if the result is a method of some kind, bind
// the base object to it
JSValue result = topValue();
if (result.isFunction()) {
if (result.isFunction() && result.function->isMethod()) {
popValue();
if (result.function->isConstructor())
// A constructor has to be called with a NULL 'this' in order to prompt it
@ -1853,16 +1875,22 @@ static JSValue compareEqual(Context *cx, JSValue r1, JSValue r2)
else {
if (r1.isUndefined())
return kTrueValue;
if (r1.isNull())
if (r1.isNull() || r2.isNull()) // because null->getType() == Object_Type
return kTrueValue;
if (r1.isObject() && r2.isObject()) // because new Boolean()->getType() == Boolean_Type
return JSValue(r1.object == r2.object);
if (r1.isType())
return JSValue(r1.type == r2.type);
if (r1.isFunction())
return JSValue(r1.function->isEqual(r2.function));
if (t1 == Number_Type) {
float64 f1 = r1.getNumberValue();
float64 f2 = r2.getNumberValue();
if (r1.isNaN())
if (JSDOUBLE_IS_NaN(f1))
return kFalseValue;
if (r2.isNaN())
if (JSDOUBLE_IS_NaN(f2))
return kFalseValue;
return JSValue(r1.f64 == r2.f64);
@ -1872,12 +1900,6 @@ static JSValue compareEqual(Context *cx, JSValue r1, JSValue r2)
return JSValue(bool(r1.getStringValue()->compare(*r2.getStringValue()) == 0));
if (t1 == Boolean_Type)
return JSValue(r1.getBoolValue() == r2.getBoolValue());
if (r1.isObject())
return JSValue(r1.object == r2.object);
if (r1.isType())
return JSValue(r1.type == r2.type);
if (r1.isFunction())
return JSValue(r1.function->isEqual(r2.function));
NOT_REACHED("unhandled type");
return kFalseValue;
}
@ -1944,7 +1966,7 @@ void Context::initOperators()
};
for (uint32 i = 0; i < sizeof(OpTable) / sizeof(OpTableEntry); i++) {
JSFunction *f = new JSFunction(OpTable[i].imp, OpTable[i].resType);
JSFunction *f = new JSFunction(this, OpTable[i].imp, OpTable[i].resType);
OperatorDefinition *op = new OperatorDefinition(OpTable[i].op1, OpTable[i].op2, f);
mOperatorTable[OpTable[i].which].push_back(op);
}
@ -2198,7 +2220,7 @@ float64 JSValue::float64ToInteger(float64 d)
if (JSDOUBLE_IS_NaN(d))
return 0.0;
else
return (d >= 0.0) ? fd::floor(d) : -fd::floor(d);
return (d >= 0.0) ? fd::floor(d) : -fd::floor(-d);
}
JSValue JSValue::valueToInteger(Context *cx, const JSValue& value)
@ -2382,6 +2404,7 @@ JSType *JSValue::getType() const {
case undefined_tag: return Void_Type;
case null_tag: return Object_Type;
case function_tag: return Function_Type;
case type_tag: return Type_Type;
default:
NOT_REACHED("bad type");
return NULL;

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

@ -654,7 +654,7 @@ void ScopeChain::setNameValue(Context *cx, const String& name, AttributeStmtNode
inline char narrow(char16 ch) { return char(ch); }
void ScopeChain::getNameValue(Context *cx, const String& name, AttributeStmtNode *attr)
JSObject *ScopeChain::getNameValue(Context *cx, const String& name, AttributeStmtNode *attr)
{
NamespaceList *names = (attr) ? attr->attributeValue->mNamespaceList : NULL;
uint32 depth = 0;
@ -670,10 +670,11 @@ void ScopeChain::getNameValue(Context *cx, const String& name, AttributeStmtNode
default:
ASSERT(false); // what else needs to be implemented ?
}
return;
return *s;
}
}
m_cx->reportError(Exception::referenceError, "'{0}' not defined", name );
return NULL;
}
Reference *ScopeChain::getName(const String& name, NamespaceList *names, Access acc)
@ -745,22 +746,22 @@ Reference *ParameterBarrel::genReference(bool /* hasBase */, const String& name,
JSType *ScopeChain::findType(const StringAtom& typeName, size_t pos)
{
JSValue v = getCompileTimeValue(typeName, NULL);
if (!v.isUndefined()) {
if (v.isType())
return v.type;
else {
// Allow finding a function that has the same name as it's containing class
// i.e. the default constructor.
FunctionName *fnName = v.function->getFunctionName();
if ((fnName->prefix == FunctionName::normal)
&& v.isFunction() && v.function->getClass()
&& (v.function->getClass()->mClassName->compare(*fnName->name) == 0))
return v.function->getClass();
m_cx->reportError(Exception::semanticError, "Unknown type", pos);
return NULL;
}
}
return NULL;
if (!v.isUndefined()) {
if (v.isType())
return v.type;
else {
// Allow finding a function that has the same name as it's containing class
// i.e. the default constructor.
FunctionName *fnName = v.function->getFunctionName();
if ((fnName->prefix == FunctionName::normal)
&& v.isFunction() && v.function->getClass()
&& (v.function->getClass()->mClassName->compare(*fnName->name) == 0))
return v.function->getClass();
m_cx->reportError(Exception::semanticError, "Unknown type", pos);
return NULL;
}
}
return NULL;
}
// Take the specified type in 't' and see if we have a compile-time
@ -990,7 +991,7 @@ void ScopeChain::collectNames(StmtNode *p)
bool isOperator = (f->attributeValue->mTrueFlags & Property::Operator) == Property::Operator;
bool isPrototype = (f->attributeValue->mTrueFlags & Property::Prototype) == Property::Prototype;
JSFunction *fnc = new JSFunction(NULL, this);
JSFunction *fnc = new JSFunction(m_cx, NULL, this);
/* Determine whether a function is unchecked, which is the case if -
XXX strict mode is disabled at the point of the function definition;
@ -1024,7 +1025,7 @@ void ScopeChain::collectNames(StmtNode *p)
optArgCount++;
b = b->next;
}
fnc->setArgCounts(reqArgCount, optArgCount, (f->function.restParameter != NULL));
fnc->setArgCounts(m_cx, reqArgCount, optArgCount, (f->function.restParameter != NULL));
if (isOperator) {
// no need to do anything yet, all operators are 'pre-declared'
@ -1139,12 +1140,9 @@ void JSType::completeClass(Context *cx, ScopeChain *scopeChain)
{
// if none exists, build a default constructor that calls 'super()'
if (getDefaultConstructor() == NULL) {
JSFunction *fnc = new JSFunction(Object_Type, scopeChain);
JSFunction *fnc = new JSFunction(cx, Object_Type, scopeChain);
fnc->setIsConstructor(true);
FunctionName *fnName = new FunctionName();
fnName->name = mClassName; //cx->mWorld.identifiers[mClassName];
fnName->prefix = FunctionName::normal;
fnc->setFunctionName(fnName);
fnc->setFunctionName(mClassName);
fnc->setClass(this);
ByteCodeGen bcg(cx, scopeChain);
@ -1343,6 +1341,7 @@ JSType::JSType(Context *cx, const StringAtom *name, JSType *super, JSObject *pro
mVariableCount(0),
mInstanceInitializer(NULL),
mDefaultConstructor(NULL),
mTypeCast(NULL),
mClassName(name),
mIsDynamic(false),
mUninitializedValue(kNullValue),
@ -1360,12 +1359,20 @@ JSType::JSType(Context *cx, const StringAtom *name, JSType *super, JSObject *pro
if (protoObj)
mPrototypeObject = protoObj;
else
mPrototypeObject = new JSObject();
mPrototypeObject = new JSObject(this);
// and that object is prototype-linked to the super-type's prototype object
if (mSuperType)
mPrototypeObject->mPrototype = mSuperType->mPrototypeObject;
// defineVariable(cx, cx->Prototype_StringAtom, NULL, Object_Type, JSValue(mPrototypeObject));
if (mSuperType)
defineVariable(cx, cx->Prototype_StringAtom, NULL, Object_Type, JSValue(mPrototypeObject));
else // must be Object_Type
defineVariable(cx, cx->Prototype_StringAtom, NULL, this, JSValue(mPrototypeObject));
if (mSuperType)
mPrototype = mSuperType->mPrototypeObject;
else // must be Object_Type
mPrototype = mPrototypeObject;
}
JSType::JSType(JSType *xClass) // used for constructing the static component type
@ -1374,6 +1381,7 @@ JSType::JSType(JSType *xClass) // used for constructing the static component
mVariableCount(0),
mInstanceInitializer(NULL),
mDefaultConstructor(NULL),
mTypeCast(NULL),
mClassName(NULL),
mPrivateNamespace(NULL),
mIsDynamic(false),
@ -1689,14 +1697,17 @@ static JSValue Object_Constructor(Context *cx, const JSValue& thisValue, JSValue
static JSValue Object_toString(Context *, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
{
if (thisValue.isObject())
return JSValue(new String(widenCString("[object ") + widenCString("Object") + widenCString("]")));
return JSValue(new String(widenCString("[object ") + *thisValue.object->getType()->mClassName + widenCString("]")));
else
if (thisValue.isType())
return JSValue(new String(widenCString("[object ") + widenCString("Type") + widenCString("]")));
else {
NOT_REACHED("Object.prototype.toString on non-object");
return kUndefinedValue;
}
else
if (thisValue.isFunction())
return JSValue(new String(widenCString("[object ") + widenCString("Function") + widenCString("]")));
else {
NOT_REACHED("Object.prototype.toString on non-object");
return kUndefinedValue;
}
}
struct IteratorDongle {
@ -1706,12 +1717,24 @@ struct IteratorDongle {
static JSValue Object_forin(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
{
ASSERT(thisValue.isObject());
JSObject *iteratorObject = Object_Type->newInstance(cx);
JSObject *obj = NULL;
if (thisValue.isType())
obj = thisValue.type;
else
if (thisValue.isFunction())
obj = thisValue.function;
else
if (thisValue.isObject())
obj = thisValue.object;
else
NOT_REACHED("Non object for for..in");
JSObject *iteratorObject = Object_Type->newInstance(cx);
IteratorDongle *itDude = new IteratorDongle();
itDude->obj = thisValue.object;
itDude->it = thisValue.object->mProperties.begin();
itDude->obj = obj;
itDude->it = obj->mProperties.begin();
if (itDude->it == itDude->obj->mProperties.end())
return kNullValue;
JSValue v(&PROPERTY_NAME(itDude->it));
iteratorObject->setProperty(cx, cx->mWorld.identifiers["value"], 0, v);
@ -1775,13 +1798,14 @@ static JSValue Function_Constructor(Context *cx, const JSValue& thisValue, JSVal
{
Arena a;
Parser p(cx->mWorld, a, cx->mFlags, s, widenCString("function constructor"));
Reader *oldReader = cx->mReader;
cx->mReader = &p.lexer.reader;
FunctionExprNode *f = p.parseFunctionExpression(0);
if (!p.lexer.peek(true).hasKind(Token::end))
cx->reportError(Exception::syntaxError, "Unexpected stuff after the function body");
fnc = new JSFunction(NULL, cx->mScopeChain);
fnc = new JSFunction(cx, NULL, cx->mScopeChain);
uint32 reqArgCount = 0;
uint32 optArgCount = 0;
@ -1795,7 +1819,7 @@ static JSValue Function_Constructor(Context *cx, const JSValue& thisValue, JSVal
optArgCount++;
b = b->next;
}
fnc->setArgCounts(reqArgCount, optArgCount, (f->function.restParameter != NULL));
fnc->setArgCounts(cx, reqArgCount, optArgCount, (f->function.restParameter != NULL));
if (cx->mScopeChain->isPossibleUncheckedFunction(&f->function))
fnc->setIsPrototype(true);
@ -1803,6 +1827,7 @@ static JSValue Function_Constructor(Context *cx, const JSValue& thisValue, JSVal
cx->buildRuntimeForFunction(f->function, fnc);
ByteCodeGen bcg(cx, cx->mScopeChain);
bcg.genCodeForFunction(f->function, f->pos, fnc, false, NULL);
cx->setReader(oldReader);
}
/***************************************************************/
@ -1917,7 +1942,8 @@ static JSValue Boolean_toString(Context *cx, const JSValue& thisValue, JSValue *
{
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
if (thisObj->mType != Boolean_Type)
cx->reportError(Exception::typeError, "Boolean.toString can only be applied to Boolean objects");
if (thisObj->mPrivate != 0)
return JSValue(&cx->True_StringAtom);
else
@ -1928,11 +1954,12 @@ static JSValue Boolean_valueOf(Context *cx, const JSValue& thisValue, JSValue *
{
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
if (thisObj->mType != Boolean_Type)
cx->reportError(Exception::typeError, "Boolean.valueOf can only be applied to Boolean objects");
if (thisObj->mPrivate != 0)
return kTrueValue; //JSValue(1.0);
return kTrueValue;
else
return kFalseValue; //kPositiveZero;
return kFalseValue;
}
static JSValue ExtendAttribute_Invoke(Context * /*cx*/, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
@ -1988,7 +2015,77 @@ static JSValue GlobalObject_ParseFloat(Context *cx, const JSValue& /*thisValue*/
return JSValue(f);
}
static JSValue GlobalObject_isNaN(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
{
float64 f = argv[0].toNumber(cx).f64;
if (JSDOUBLE_IS_NaN(f))
return kTrueValue;
else
return kFalseValue;
}
static JSValue GlobalObject_isFinite(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
{
float64 f = argv[0].toNumber(cx).f64;
if (JSDOUBLE_IS_FINITE(f))
return kTrueValue;
else
return kFalseValue;
}
JSFunction::JSFunction(Context *cx, JSType *resultType, ScopeChain *scopeChain)
: JSObject(Function_Type),
mParameterBarrel(NULL),
mActivation(),
mByteCode(NULL),
mCode(NULL),
mResultType(resultType),
mRequiredArgs(0),
mOptionalArgs(0),
mArguments(NULL),
mScopeChain(NULL),
mIsPrototype(false),
mIsConstructor(false),
mIsChecked(true),
mHasRestParameter(false),
mRestParameterName(NULL),
mClass(NULL),
mFunctionName(NULL)
{
if (scopeChain) {
mScopeChain = new ScopeChain(*scopeChain);
}
if (Function_Type) // protect against bootstrap
mPrototype = Function_Type->mPrototypeObject;
mActivation.mContainer = this;
defineVariable(cx, cx->Length_StringAtom, (NamespaceList *)NULL, Number_Type, JSValue((float64)0));
}
JSFunction::JSFunction(Context *cx, NativeCode *code, JSType *resultType)
: JSObject(Function_Type),
mParameterBarrel(NULL),
mActivation(),
mByteCode(NULL),
mCode(code),
mResultType(resultType),
mRequiredArgs(0),
mOptionalArgs(0),
mArguments(NULL),
mScopeChain(NULL),
mIsPrototype(false),
mIsConstructor(false),
mIsChecked(false), // native functions aren't checked (?)
mHasRestParameter(false),
mRestParameterName(NULL),
mClass(NULL),
mFunctionName(NULL)
{
if (Function_Type) // protect against bootstrap
mPrototype = Function_Type->mPrototypeObject;
mActivation.mContainer = this;
defineVariable(cx, cx->Length_StringAtom, (NamespaceList *)NULL, Number_Type, JSValue((float64)0));
}
JSValue JSFunction::runArgInitializer(Context *cx, uint32 a, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
@ -1996,12 +2093,13 @@ JSValue JSFunction::runArgInitializer(Context *cx, uint32 a, const JSValue& this
return cx->interpret(getByteCode(), (int32)mArguments[a].mInitializer, getScopeChain(), thisValue, argv, argc);
}
void JSFunction::setArgCounts(uint32 r, uint32 o, bool hasRest)
void JSFunction::setArgCounts(Context *cx, uint32 r, uint32 o, bool hasRest)
{
mHasRestParameter = hasRest;
mRequiredArgs = r;
mOptionalArgs = o;
mArguments = new ArgumentData[mRequiredArgs + mOptionalArgs + ((hasRest) ? 1 : 0)];
setProperty(cx, cx->Length_StringAtom, (NamespaceList *)NULL, JSValue((float64)mRequiredArgs));
}
@ -2036,22 +2134,19 @@ void Context::assureStackSpace(uint32 s)
void Context::initClass(JSType *type, ClassDef *cdef, PrototypeFunctions *pdef)
{
mScopeChain->addScope(type);
JSFunction *constructor = new JSFunction(cdef->defCon, Object_Type);
JSFunction *constructor = new JSFunction(this, cdef->defCon, Object_Type);
constructor->setClass(type);
FunctionName *fnName = new FunctionName();
fnName->name = type->mClassName;
constructor->setFunctionName(fnName);
constructor->setFunctionName(type->mClassName);
type->setDefaultConstructor(this, constructor);
// the prototype functions are defined in the prototype object...
if (pdef) {
for (uint32 i = 0; i < pdef->mCount; i++) {
JSFunction *fun = new JSFunction(pdef->mDef[i].imp, pdef->mDef[i].result);
fun->setClass(type);
JSFunction *fun = new JSFunction(this, pdef->mDef[i].imp, pdef->mDef[i].result);
// fun->setClass(type); don't do this, it makes the function a method
StringAtom *name = &mWorld.identifiers[widenCString(pdef->mDef[i].name)];
FunctionName *fnName = new FunctionName();
fun->setFunctionName(fnName);
fun->setArgCounts(pdef->mDef[i].length, 0, false);
fun->setFunctionName(name);
fun->setArgCounts(this, pdef->mDef[i].length, 0, false);
type->mPrototypeObject->defineVariable(this, *name,
(NamespaceList *)(NULL),
pdef->mDef[i].result,
@ -2106,6 +2201,7 @@ void Context::initBuiltins()
};
Object_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[0].name)], NULL);
Object_Type->mPrototype->mType = Object_Type;
Object_Type->mIsDynamic = true;
// XXX aren't all the built-ins thus?
@ -2119,34 +2215,26 @@ void Context::initBuiltins()
// (which we don't actually have, hmm).
// For String, etc. this same issue needs to be finessed
JSFunction *funProto = new JSFunction(Object_Type, NULL);
JSFunction *funProto = new JSFunction(this, Object_Type, NULL);
Function_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[2].name)], Object_Type, funProto);
Function_Type->defineVariable(this, Prototype_StringAtom, NULL, Object_Type, JSValue(funProto));
funProto->mType = Function_Type;
Number_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[3].name)], Object_Type);
Number_Type->defineVariable(this, Prototype_StringAtom, NULL, Object_Type, JSValue(Number_Type->mPrototypeObject));
Integer_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[4].name)], Object_Type);
String_Type = new JSStringType(this, &mWorld.identifiers[widenCString(builtInClasses[5].name)], Object_Type);
String_Type->defineVariable(this, Prototype_StringAtom, NULL, Object_Type, JSValue(String_Type->mPrototypeObject));
Array_Type = new JSArrayType(this, Object_Type, &mWorld.identifiers[widenCString(builtInClasses[6].name)], Object_Type);
Array_Type->defineVariable(this, Prototype_StringAtom, NULL, Object_Type, JSValue(Array_Type->mPrototypeObject));
Boolean_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[7].name)], Object_Type);
Boolean_Type->defineVariable(this, Prototype_StringAtom, NULL, Object_Type, JSValue(Boolean_Type->mPrototypeObject));
JSArrayInstance *arrayProto = new JSArrayInstance(this, NULL);
Array_Type = new JSArrayType(this, Object_Type, &mWorld.identifiers[widenCString(builtInClasses[6].name)], Object_Type, arrayProto);
arrayProto->mType = Array_Type;
Boolean_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[7].name)], Object_Type);
Void_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[8].name)], Object_Type);
Unit_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[9].name)], Object_Type);
Attribute_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[10].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->defineVariable(this, Prototype_StringAtom, NULL, Object_Type, JSValue(Date_Type->mPrototypeObject));
String_Type->defineVariable(this, FromCharCode_StringAtom, NULL, String_Type, JSValue(new JSFunction(String_fromCharCode, String_Type)));
String_Type->defineVariable(this, FromCharCode_StringAtom, NULL, String_Type, JSValue(new JSFunction(this, String_fromCharCode, String_Type)));
ProtoFunDef objectProtos[] =
@ -2203,10 +2291,14 @@ void Context::initBuiltins()
initClass(NamedArgument_Type, &builtInClasses[11], NULL);
initClass(Date_Type, &builtInClasses[12], getDateProtos() );
Type_Type->defineUnaryOperator(Index, new JSFunction(arrayMaker, Type_Type));
Type_Type->defineUnaryOperator(Index, new JSFunction(this, arrayMaker, Type_Type));
Array_Type->defineUnaryOperator(Index, new JSFunction(Array_GetElement, Object_Type));
Array_Type->defineUnaryOperator(IndexEqual, new JSFunction(Array_SetElement, Object_Type));
Array_Type->defineUnaryOperator(Index, new JSFunction(this, Array_GetElement, Object_Type));
Array_Type->defineUnaryOperator(IndexEqual, new JSFunction(this, Array_SetElement, Object_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));
}
@ -2382,21 +2474,23 @@ Context::Context(JSObject **global, World &world, Arena &a, Pragma::Flags flags)
getGlobalObject()->defineVariable(this, widenCString(attribute_init[i].name), (NamespaceList *)(NULL), Attribute_Type, JSValue(attr));
}
JSFunction *x = new JSFunction(ExtendAttribute_Invoke, Attribute_Type);
JSFunction *x = new JSFunction(this, ExtendAttribute_Invoke, Attribute_Type);
getGlobalObject()->defineVariable(this, Extend_StringAtom, (NamespaceList *)(NULL), Attribute_Type, JSValue(x));
ProtoFunDef globalObjectFunctions[] = {
{ "eval", Object_Type, 1, GlobalObject_Eval },
{ "parseInt", Number_Type, 2, GlobalObject_ParseInt },
{ "parseFloat", Number_Type, 2, GlobalObject_ParseFloat },
{ "eval", Object_Type, 1, GlobalObject_Eval },
{ "parseInt", Number_Type, 2, GlobalObject_ParseInt },
{ "parseFloat", Number_Type, 2, GlobalObject_ParseFloat },
{ "isNaN", Boolean_Type, 2, GlobalObject_isNaN },
{ "isFinite", Boolean_Type, 2, GlobalObject_isFinite },
};
for (i = 0; i < (sizeof(globalObjectFunctions) / sizeof(ProtoFunDef)); i++) {
x = new JSFunction(globalObjectFunctions[i].imp, globalObjectFunctions[i].result);
x->setArgCounts(globalObjectFunctions[i].length, 0, false);
x = new JSFunction(this, globalObjectFunctions[i].imp, globalObjectFunctions[i].result);
x->setArgCounts(this, globalObjectFunctions[i].length, 0, false);
x->setIsPrototype(true);
getGlobalObject()->defineVariable(this, widenCString(globalObjectFunctions[i].name), (NamespaceList *)(NULL), globalObjectFunctions[i].result, JSValue(x));
}

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

@ -385,6 +385,7 @@ XXX ...couldn't get this to work...
void emitInvokeSequence(ByteCodeGen *bcg);
void emitImplicitLoad(ByteCodeGen *bcg);
uint16 baseExpressionDepth() { return 1; }
void emitDelete(ByteCodeGen *bcg);
};
// a member function in a vtable
class MethodReference : public Reference {
@ -482,7 +483,7 @@ XXX ...couldn't get this to work...
Access mAccess;
uint16 mDepth;
void emitCodeSequence(ByteCodeGen *bcg);
uint16 baseExpressionDepth() { return mDepth; }
uint16 baseExpressionDepth() { return mDepth + 1; }
void emitDelete(ByteCodeGen *bcg);
};
@ -752,6 +753,7 @@ XXX ...couldn't get this to work...
virtual Reference *genReference(bool hasBase, const String& name, NamespaceList *names, Access acc, uint32 depth);
JSFunction *getDefaultConstructor() { return mDefaultConstructor; }
JSFunction *getTypeCastFunction() { return mTypeCast; }
JSValue getUninitializedValue() { return mUninitializedValue; }
@ -765,6 +767,7 @@ XXX ...couldn't get this to work...
uint32 mVariableCount;
JSFunction *mInstanceInitializer;
JSFunction *mDefaultConstructor;
JSFunction *mTypeCast;
// the 'vtable'
MethodList mMethods;
@ -806,8 +809,8 @@ XXX ...couldn't get this to work...
class JSArrayType : public JSType {
public:
JSArrayType(Context *cx, JSType *elementType, const StringAtom *name, JSType *super)
: JSType(cx, name, super), mElementType(elementType)
JSArrayType(Context *cx, JSType *elementType, const StringAtom *name, JSType *super, JSObject *protoObj = NULL)
: JSType(cx, name, super, protoObj), mElementType(elementType)
{
}
virtual ~JSArrayType() { } // keeping gcc happy
@ -1084,7 +1087,8 @@ XXX ...couldn't get this to work...
bool hasNameValue(const String& name, NamespaceList *names);
void getNameValue(Context *cx, const String& name, AttributeStmtNode *attr);
// pushes the value of the name and returns it's container object
JSObject *getNameValue(Context *cx, const String& name, AttributeStmtNode *attr);
// return the class on the top of the stack (or NULL if there
// isn't one there).
@ -1180,54 +1184,8 @@ XXX ...couldn't get this to work...
// XXX these should be Function_Type->newInstance() calls, no?
JSFunction(JSType *resultType, ScopeChain *scopeChain)
: JSObject(Function_Type),
mParameterBarrel(NULL),
mActivation(),
mByteCode(NULL),
mCode(NULL),
mResultType(resultType),
mRequiredArgs(0),
mOptionalArgs(0),
mArguments(NULL),
mScopeChain(NULL),
mIsPrototype(false),
mIsConstructor(false),
mIsChecked(true),
mHasRestParameter(false),
mRestParameterName(NULL),
mClass(NULL)
{
if (scopeChain) {
mScopeChain = new ScopeChain(*scopeChain);
}
if (Function_Type) // protect against bootstrap
mPrototype = Function_Type->mPrototypeObject;
mActivation.mContainer = this;
}
JSFunction(NativeCode *code, JSType *resultType)
: JSObject(Function_Type),
mParameterBarrel(NULL),
mActivation(),
mByteCode(NULL),
mCode(code),
mResultType(resultType),
mRequiredArgs(0),
mOptionalArgs(0),
mArguments(NULL),
mScopeChain(NULL),
mIsPrototype(false),
mIsConstructor(false),
mIsChecked(false), // native functions aren't checked (?)
mHasRestParameter(false),
mRestParameterName(NULL),
mClass(NULL)
{
if (Function_Type) // protect against bootstrap
mPrototype = Function_Type->mPrototypeObject;
mActivation.mContainer = this;
}
JSFunction(Context *cx, JSType *resultType, ScopeChain *scopeChain);
JSFunction(Context *cx, NativeCode *code, JSType *resultType);
~JSFunction() { } // keeping gcc happy
@ -1238,7 +1196,7 @@ XXX ...couldn't get this to work...
void setByteCode(ByteCodeModule *b) { ASSERT(!isNative()); mByteCode = b; }
void setResultType(JSType *r) { mResultType = r; }
void setArgCounts(uint32 r, uint32 o, bool hasRest);
void setArgCounts(Context *cx, uint32 r, uint32 o, bool hasRest);
void setArgument(uint32 index, const String *n, JSType *t)
{ ASSERT(mArguments && (index < (mRequiredArgs + mOptionalArgs + ((mHasRestParameter) ? 1 : 0) ))); mArguments[index].mType = t; mArguments[index].mName = n; }
void setArgumentInitializer(uint32 index, uint32 offset)
@ -1247,13 +1205,16 @@ XXX ...couldn't get this to work...
void setIsPrototype(bool i) { mIsPrototype = i; }
void setIsConstructor(bool i) { mIsConstructor = i; }
void setIsUnchecked() { mIsChecked = false; }
void setFunctionName(FunctionName *n) { mFunctionName = n; }
void setFunctionName(FunctionName *n) { mFunctionName = new FunctionName(); mFunctionName->prefix = n->prefix; mFunctionName->name = n->name; }
void setFunctionName(const StringAtom *n)
{ mFunctionName = new FunctionName(); mFunctionName->name = n; }
void setClass(JSType *c) { mClass = c; }
virtual bool hasBoundThis() { return false; }
virtual bool isNative() { return (mCode != NULL); }
virtual bool isPrototype() { return mIsPrototype; }
virtual bool isConstructor() { return mIsConstructor; }
bool isMethod() { return (mClass != NULL); }
virtual ByteCodeModule *getByteCode() { ASSERT(!isNative()); return mByteCode; }
virtual NativeCode *getNativeCode() { ASSERT(isNative()); return mCode; }

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

@ -108,6 +108,21 @@ static float64 firstDayOfMonth[2][12] = {
#define DayWithinYear(t, year) ((int32)(Day(t) - DayFromYear(year)))
typedef enum formatspec {
FORMATSPEC_FULL, FORMATSPEC_DATE, FORMATSPEC_TIME
} formatspec;
/* constants for toString, toUTCString */
static char js_NaN_date_str[] = "Invalid Date";
static const char* days[] =
{
"Sun","Mon","Tue","Wed","Thu","Fri","Sat"
};
static const char* months[] =
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
static float64 DaylightSavingTA(float64 t)
@ -607,133 +622,6 @@ syntax:
return nan;
}
#define MAXARGS 7
JSValue Date_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
JSValue thatValue = thisValue;
if (thatValue.isNull())
thatValue = Date_Type->newInstance(cx);
ASSERT(thatValue.isObject());
JSObject *thisObj = thatValue.object;
thisObj->mPrivate = new float64;
#if 0
/* Date called as function */
if (!cx->fp->constructing) {
int64 us, ms, us2ms;
jsdouble msec_time;
/* NSPR 2.0 docs say 'We do not support PRMJ_NowMS and PRMJ_NowS',
* so compute ms from PRMJ_Now.
*/
us = PRMJ_Now();
JSLL_UI2L(us2ms, PRMJ_USEC_PER_MSEC);
JSLL_DIV(ms, us, us2ms);
JSLL_L2D(msec_time, ms);
return date_format(cx, msec_time, FORMATSPEC_FULL, rval);
}
#endif
/* Date called as constructor */
if (argc == 0) {
int64 us, ms, us2ms;
float64 msec_time;
us = PRMJ_Now();
JSLL_UI2L(us2ms, PRMJ_USEC_PER_MSEC);
JSLL_DIV(ms, us, us2ms);
JSLL_L2D(msec_time, ms);
*((float64 *)(thisObj->mPrivate)) = msec_time;
}
else {
if (argc == 1) {
if (!argv[0].isString()) {
/* the argument is a millisecond number */
float64 d = argv[0].toNumber(cx).f64;
*((float64 *)(thisObj->mPrivate)) = TIMECLIP(d);
} else {
/* the argument is a string; parse it. */
const String *str = argv[0].toString(cx).string;
double d = date_parseString(*str);
*((float64 *)(thisObj->mPrivate)) = TIMECLIP(d);
}
}
else {
float64 array[MAXARGS];
uint32 loop;
float64 day;
float64 msec_time;
for (loop = 0; loop < MAXARGS; loop++) {
if (loop < argc) {
float64 double_arg = argv[loop].toNumber(cx).f64;
/* if any arg is NaN, make a NaN date object
and return */
if (!JSDOUBLE_IS_FINITE(double_arg)) {
*((float64 *)(thisObj->mPrivate)) = nan;
return thatValue;
}
array[loop] = JSValue::float64ToInteger(double_arg);
} else {
if (loop == 2) {
array[loop] = 1; /* Default the date argument to 1. */
} else {
array[loop] = 0;
}
}
}
/* adjust 2-digit years into the 20th century */
if (array[0] >= 0 && array[0] <= 99)
array[0] += 1900;
day = MakeDay(array[0], array[1], array[2]);
msec_time = MakeTime(array[3], array[4], array[5], array[6]);
msec_time = MakeDate(day, msec_time);
msec_time = UTC(msec_time);
*((float64 *)(thisObj->mPrivate)) = TIMECLIP(msec_time);
}
}
return thatValue;
}
/* constants for toString, toUTCString */
static char js_NaN_date_str[] = "Invalid Date";
static const char* days[] =
{
"Sun","Mon","Tue","Wed","Thu","Fri","Sat"
};
static const char* months[] =
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
static JSValue Date_toGMTString(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
{
StringFormatter buf;
float64 *date = Date_getProlog(cx, thisValue);
if (!JSDOUBLE_IS_FINITE(*date)) {
buf << js_NaN_date_str;
} else {
float64 temp = *date;
/* Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
* requires a PRMJTime... which only has 16-bit years. Sub-ECMA.
*/
printFormat(buf, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
days[WeekDay(temp)],
DateFromTime(temp),
months[MonthFromTime(temp)],
YearFromTime(temp),
HourFromTime(temp),
MinFromTime(temp),
SecFromTime(temp));
}
return JSValue(new String(buf.getString()));
}
/* for Date.toLocaleString; interface to PRMJTime date struct.
* If findEquivalent is true, then try to map the year to an equivalent year
@ -779,11 +667,6 @@ static void new_explode(float64 timeval, PRMJTime *split, bool findEquivalent)
split->tm_isdst = (DaylightSavingTA(timeval) != 0);
}
typedef enum formatspec {
FORMATSPEC_FULL, FORMATSPEC_DATE, FORMATSPEC_TIME
} formatspec;
/* helper function */
static JSValue Date_format(Context * /*cx*/, float64 date, formatspec format)
{
@ -887,6 +770,163 @@ static JSValue Date_format(Context * /*cx*/, float64 date, formatspec format)
return JSValue(new String(outf.getString()));
}
extern JSValue Date_TypeCast(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
int64 us, ms, us2ms;
float64 msec_time;
/* NSPR 2.0 docs say 'We do not support PRMJ_NowMS and PRMJ_NowS',
* so compute ms from PRMJ_Now.
*/
us = PRMJ_Now();
JSLL_UI2L(us2ms, PRMJ_USEC_PER_MSEC);
JSLL_DIV(ms, us, us2ms);
JSLL_L2D(msec_time, ms);
return Date_format(cx, msec_time, FORMATSPEC_FULL);
}
#define MAXARGS 7
JSValue Date_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
JSValue thatValue = thisValue;
if (thatValue.isNull())
thatValue = Date_Type->newInstance(cx);
ASSERT(thatValue.isObject());
JSObject *thisObj = thatValue.object;
thisObj->mPrivate = new float64;
/* Date called as constructor */
if (argc == 0) {
int64 us, ms, us2ms;
float64 msec_time;
us = PRMJ_Now();
JSLL_UI2L(us2ms, PRMJ_USEC_PER_MSEC);
JSLL_DIV(ms, us, us2ms);
JSLL_L2D(msec_time, ms);
*((float64 *)(thisObj->mPrivate)) = msec_time;
}
else {
if (argc == 1) {
if (!argv[0].isString()) {
/* the argument is a millisecond number */
float64 d = argv[0].toNumber(cx).f64;
*((float64 *)(thisObj->mPrivate)) = TIMECLIP(d);
} else {
/* the argument is a string; parse it. */
const String *str = argv[0].toString(cx).string;
float64 d = date_parseString(*str);
*((float64 *)(thisObj->mPrivate)) = TIMECLIP(d);
}
}
else {
float64 array[MAXARGS];
uint32 loop;
float64 day;
float64 msec_time;
for (loop = 0; loop < MAXARGS; loop++) {
if (loop < argc) {
float64 double_arg = argv[loop].toNumber(cx).f64;
/* if any arg is NaN, make a NaN date object
and return */
if (!JSDOUBLE_IS_FINITE(double_arg)) {
*((float64 *)(thisObj->mPrivate)) = nan;
return thatValue;
}
array[loop] = JSValue::float64ToInteger(double_arg);
} else {
if (loop == 2) {
array[loop] = 1; /* Default the date argument to 1. */
} else {
array[loop] = 0;
}
}
}
/* adjust 2-digit years into the 20th century */
if (array[0] >= 0 && array[0] <= 99)
array[0] += 1900;
day = MakeDay(array[0], array[1], array[2]);
msec_time = MakeTime(array[3], array[4], array[5], array[6]);
msec_time = MakeDate(day, msec_time);
msec_time = UTC(msec_time);
*((float64 *)(thisObj->mPrivate)) = TIMECLIP(msec_time);
}
}
return thatValue;
}
JSValue Date_parse(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 /*argc*/)
{
const String *str = argv[0].toString(cx).string;
float64 d = date_parseString(*str);
d = TIMECLIP(d);
return JSValue(d);
}
JSValue Date_UTC(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
float64 array[MAXARGS];
uint32 loop;
float64 d;
for (loop = 0; loop < MAXARGS; loop++) {
if (loop < argc) {
d = argv[loop].toNumber(cx).f64;
if (!JSDOUBLE_IS_FINITE(d))
return JSValue(d);
array[loop] = floor(d);
}
else
array[loop] = 0;
}
/* adjust 2-digit years into the 20th century */
if ((array[0] >= 0) && (array[0] <= 99))
array[0] += 1900;
/* if we got a 0 for 'date' (which is out of range)
* pretend it's a 1. (So Date.UTC(1972, 5) works) */
if (array[2] < 1)
array[2] = 1;
d = date_msecFromDate(array[0], array[1], array[2],
array[3], array[4], array[5], array[6]);
d = TIMECLIP(d);
return JSValue(d);
}
static JSValue Date_toGMTString(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
{
StringFormatter buf;
float64 *date = Date_getProlog(cx, thisValue);
if (!JSDOUBLE_IS_FINITE(*date)) {
buf << js_NaN_date_str;
} else {
float64 temp = *date;
/* Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
* requires a PRMJTime... which only has 16-bit years. Sub-ECMA.
*/
printFormat(buf, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
days[WeekDay(temp)],
DateFromTime(temp),
months[MonthFromTime(temp)],
YearFromTime(temp),
HourFromTime(temp),
MinFromTime(temp),
SecFromTime(temp));
}
return JSValue(new String(buf.getString()));
}
static JSValue Date_toLocaleHelper(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/, char *format)
{
StringFormatter outf;
@ -1341,6 +1381,7 @@ Context::PrototypeFunctions *getDateProtos()
{ "setMilliseconds", Number_Type, 1, Date_setMilliseconds },
{ "setUTCMilliseconds", Number_Type, 1, Date_setUTCMilliseconds },
{ "toUTCString", String_Type, 0, Date_toGMTString },
{ "toGMTString", String_Type, 0, Date_toGMTString }, // XXX this is a SpiderMonkey extension?
{ "toLocaleString", String_Type, 0, Date_toLocaleString },
{ "toLocaleDateString", String_Type, 0, Date_toLocaleDateString },
{ "toLocaleTimeString", String_Type, 0, Date_toLocaleTimeString },

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

@ -37,6 +37,9 @@ namespace JS2Runtime {
extern JSValue Date_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc);
extern JSValue Date_TypeCast(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc);
extern JSValue Date_parse(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc);
extern JSValue Date_UTC(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc);
Context::PrototypeFunctions *getDateProtos();

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

@ -249,7 +249,7 @@ void initMathObject(Context *cx, JSObject *mathObj)
(NamespaceList *)(NULL), Number_Type, JSValue(MathObjectConstants[i].value));
for (i = 0; i < sizeof(MathObjectFunctions) / sizeof(MathObjectFunctionDef); i++) {
JSFunction *f = new JSFunction(MathObjectFunctions[i].imp, Number_Type);
JSFunction *f = new JSFunction(cx, MathObjectFunctions[i].imp, Number_Type);
mathObj->defineVariable(cx, widenCString(MathObjectFunctions[i].name),
(NamespaceList *)(NULL), Number_Type, JSValue(f));
}

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

@ -257,12 +257,12 @@ int main(int argc, char **argv)
JSObject *globalObject;
Context cx(&globalObject, world, a, Pragma::js2);
globalObject->defineVariable(&cx, widenCString("load"), (NamespaceList *)(NULL), NULL, JSValue(new JSFunction(load, NULL)));
globalObject->defineVariable(&cx, widenCString("print"), (NamespaceList *)(NULL), NULL, JSValue(new JSFunction(print, NULL)));
globalObject->defineVariable(&cx, widenCString("debug"), (NamespaceList *)(NULL), NULL, JSValue(new JSFunction(debug, NULL)));
globalObject->defineVariable(&cx, widenCString("trace"), (NamespaceList *)(NULL), NULL, JSValue(new JSFunction(trace, NULL)));
globalObject->defineVariable(&cx, widenCString("dikdik"), (NamespaceList *)(NULL), NULL, JSValue(new JSFunction(dikdik, NULL)));
globalObject->defineVariable(&cx, widenCString("version"), (NamespaceList *)(NULL), NULL, JSValue(new JSFunction(version, NULL)));
globalObject->defineVariable(&cx, widenCString("load"), (NamespaceList *)(NULL), NULL, JSValue(new JSFunction(&cx, load, NULL)));
globalObject->defineVariable(&cx, widenCString("print"), (NamespaceList *)(NULL), NULL, JSValue(new JSFunction(&cx, print, NULL)));
globalObject->defineVariable(&cx, widenCString("debug"), (NamespaceList *)(NULL), NULL, JSValue(new JSFunction(&cx, debug, NULL)));
globalObject->defineVariable(&cx, widenCString("trace"), (NamespaceList *)(NULL), NULL, JSValue(new JSFunction(&cx, trace, NULL)));
globalObject->defineVariable(&cx, widenCString("dikdik"), (NamespaceList *)(NULL), NULL, JSValue(new JSFunction(&cx, dikdik, NULL)));
globalObject->defineVariable(&cx, widenCString("version"), (NamespaceList *)(NULL), NULL, JSValue(new JSFunction(&cx, version, NULL)));
bool doInteractive = true;
int result = 0;

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

@ -41,7 +41,7 @@ RSC=rc.exe
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /I "../../src" /D "_CONSOLE" /D "NDEBUG" /D "WIN32" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /I "../../src" /D "_CONSOLE" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "XP_PC" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
@ -65,7 +65,7 @@ LINK32=link.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GR /GX /ZI /Od /I "../../src" /D "_CONSOLE" /D "DEBUG" /D "_DEBUG" /D "WIN32" /D "_MBCS" /FR /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GR /GX /ZI /Od /I "../../src" /D "_CONSOLE" /D "DEBUG" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "XP_PC" /FR /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe