Sweeping changes arising from moving unary operator table to context etc.

This commit is contained in:
rogerl%netscape.com 2002-02-21 18:06:35 +00:00
Родитель 6c83a2be82
Коммит 2cc1770789
10 изменённых файлов: 2051 добавлений и 1576 удалений

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

@ -99,6 +99,7 @@ void ClosureVarReference::emitCodeSequence(ByteCodeGen *bcg)
void StaticFieldReference::emitImplicitLoad(ByteCodeGen *bcg)
{
bcg->addOp(LoadTypeOp);
ASSERT(mClass);
bcg->addPointer(mClass);
}
@ -577,6 +578,7 @@ void ByteCodeGen::genCodeForFunction(FunctionDefinition &f, size_t pos, JSFuncti
// incoming 'this' is null
//
addOp(LoadTypeOp);
ASSERT(topClass);
addPointer(topClass);
addOp(NewThisOp);
//
@ -1207,6 +1209,7 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3
genExpr(e->expr);
if (container->getResultType() != Object_Type) {
addOp(LoadTypeOp);
ASSERT(container->getResultType());
addPointer(container->getResultType());
addOp(CastOp);
}
@ -1892,6 +1895,7 @@ BinaryOpEquals:
if (writeRef->mType != Object_Type) {
addOp(LoadTypeOp);
ASSERT(writeRef->mType);
addPointer(writeRef->mType);
addOp(CastOp);
}
@ -1934,6 +1938,7 @@ BinaryOpEquals:
if (writeRef->mType != Object_Type) {
addOp(LoadTypeOp);
ASSERT(writeRef->mType);
addPointer(writeRef->mType);
addOp(CastOp);
}
@ -1975,6 +1980,7 @@ BinaryOpEquals:
if (writeRef->mType != Object_Type) {
addOp(LoadTypeOp);
ASSERT(writeRef->mType);
addPointer(writeRef->mType);
addOp(CastOp);
}
@ -2010,6 +2016,7 @@ BinaryOpEquals:
if (writeRef->mType != Object_Type) {
addOp(LoadTypeOp);
ASSERT(writeRef->mType);
addPointer(writeRef->mType);
addOp(CastOp);
}
@ -2084,6 +2091,7 @@ BinaryOpEquals:
if (ref->mType != Object_Type) {
addOp(LoadTypeOp);
ASSERT(ref->mType);
addPointer(ref->mType);
addOp(CastOp);
}
@ -2279,6 +2287,7 @@ BinaryOpEquals:
case ExprNode::arrayLiteral:
{
addOp(LoadTypeOp);
ASSERT(Array_Type);
addPointer(Array_Type);
addOpAdjustDepth(NewInstanceOp, 0);
addLong(0);
@ -2336,6 +2345,7 @@ BinaryOpEquals:
NumUnitExprNode *n = checked_cast<NumUnitExprNode *>(p);
addOp(LoadTypeOp);
ASSERT(Unit_Type);
addPointer(Unit_Type);
addOp(GetInvokePropertyOp);
addStringRef(n->str);
@ -2352,6 +2362,7 @@ BinaryOpEquals:
{
FunctionExprNode *f = checked_cast<FunctionExprNode *>(p);
JSFunction *fnc = new JSFunction(m_cx, NULL, mScopeChain);
fnc->setResultType(Object_Type);
fnc->countParameters(m_cx, f->function);
if (mScopeChain->isPossibleUncheckedFunction(f->function))
fnc->setIsPrototype(true);
@ -2435,9 +2446,9 @@ BinaryOpEquals:
m_cx->mCurModule = &errorHandlingModule;
reValue = RegExp_Constructor(m_cx, reValue, args, 2);
m_cx->mCurModule = curModule;
ASSERT(reValue.isObject());
ASSERT(reValue.isInstance());
addOp(LoadConstantRegExpOp);
addPointer(reValue.object);
addPointer(reValue.instance);
return RegExp_Type;
}
break;

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

@ -132,8 +132,8 @@ bool Context::executeOperator(Operator op, JSType *t1, JSType *t2)
// look in the operator table for applicable operators
OperatorList applicableOperators;
for (OperatorList::iterator oi = mOperatorTable[op].begin(),
end = mOperatorTable[op].end();
for (OperatorList::iterator oi = mBinaryOperatorTable[op].begin(),
end = mBinaryOperatorTable[op].end();
(oi != end); oi++)
{
if ((*oi)->isApplicable(t1, t2)) {
@ -146,12 +146,13 @@ bool Context::executeOperator(Operator op, JSType *t1, JSType *t2)
OperatorList::iterator candidate = applicableOperators.begin();
for (OperatorList::iterator aoi = applicableOperators.begin() + 1,
aend = applicableOperators.end();
(aoi != aend); aoi++)
(aoi != aend); aoi++)
{
if ((*aoi)->mType1->derivesFrom((*candidate)->mType1)
|| ((*aoi)->mType2->derivesFrom((*candidate)->mType2)))
candidate = aoi;
}
// XXX how to complain if there is more than one best fit?
JSFunction *target = (*candidate)->mImp;
@ -320,7 +321,7 @@ JSValue *Context::buildArgumentBlock(JSFunction *target, uint32 &argCount)
if (target->parameterIsRequired(pIndex)) {
if (inArgIndex < argCount) {
JSValue v = getValue(inArgIndex + argStart);
bool isPositionalArg = !(v.isObject() && (v.object->mType == NamedArgument_Type));
bool isPositionalArg = !v.isNamedArg();
// if the next argument is named, then we've run out of positional args
if (!isPositionalArg) {
if (!target->isChecked())
@ -340,7 +341,7 @@ JSValue *Context::buildArgumentBlock(JSFunction *target, uint32 &argCount)
bool tookPositionalArg = false;
if (inArgIndex < argCount) {
JSValue v = getValue(inArgIndex + argStart);
if (!(v.isObject() && (v.object->mType == NamedArgument_Type))) {
if (!v.isNamedArg()) {
argBase[pIndex] = v;
argUsed[inArgIndex++] = true;
needDefault = false;
@ -353,10 +354,9 @@ JSValue *Context::buildArgumentBlock(JSFunction *target, uint32 &argCount)
for (uint32 i = inArgIndex; i < argCount; i++) {
if (!argUsed[i]) {
JSValue v = getValue(i + argStart);
if (v.isObject() && (v.object->mType == NamedArgument_Type)) {
NamedArgument *arg = static_cast<NamedArgument *>(v.object);
if (arg->mName == parameterName) {
argBase[pIndex] = arg->mValue;
if (v.isNamedArg()) {
if (v.namedArg->mName == parameterName) {
argBase[pIndex] = v.namedArg->mValue;
argUsed[i] = true;
needDefault = false;
break;
@ -390,16 +390,16 @@ JSValue *Context::buildArgumentBlock(JSFunction *target, uint32 &argCount)
if (target->hasRestParameter() && target->getParameterName(restParameterIndex)) {
restArgument = target->getParameterType(restParameterIndex)->newInstance(this);
argBase[restParameterIndex] = JSValue(restArgument);
argBase[restParameterIndex] = restArgument;
haveRestArg = true;
}
inArgIndex = 0; // re-number the non-named arguments that end up in the rest arg
for (i = 0; i < argCount; i++) {
if (!argUsed[i]) {
JSValue v = getValue(i + argStart);
bool isNamedArg = v.isObject() && (v.object->mType == NamedArgument_Type);
bool isNamedArg = v.isNamedArg();
if (isNamedArg) {
NamedArgument *arg = static_cast<NamedArgument *>(v.object);
NamedArgument *arg = v.namedArg;
if (haveRestArg)
restArgument.object->setProperty(this, *arg->mName, (NamespaceList *)(NULL), arg->mValue);
else
@ -414,10 +414,8 @@ JSValue *Context::buildArgumentBlock(JSFunction *target, uint32 &argCount)
if (target->isChecked())
reportError(Exception::referenceError, "Extra argument, no rest argument");
else {
if (isNamedArg) {
NamedArgument *arg = static_cast<NamedArgument *>(v.object);
argBase[i] = arg->mValue;
}
if (isNamedArg)
argBase[i] = v.namedArg->mValue;
else
argBase[i] = v;
}
@ -683,10 +681,10 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
mScopeChain->addScope(target->getActivation());
if (!target->isChecked()) {
JSArrayInstance *args = (JSArrayInstance *)Array_Type->newInstance(this);
JSValue args = Array_Type->newInstance(this);
for (uint32 i = 0; i < argCount; i++)
args->setProperty(this, *numberToString(i), NULL, argBase[i]);
target->getActivation()->setProperty(this, Arguments_StringAtom, NULL, JSValue(args));
args.instance->setProperty(this, *numberToString(i), NULL, argBase[i]);
target->getActivation()->setProperty(this, Arguments_StringAtom, NULL, args);
}
mCurModule = target->getByteCode();
@ -825,8 +823,8 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
break;
case LoadConstantRegExpOp:
{
JSObject *t = *((JSObject **)pc);
pc += sizeof(JSObject *);
JSInstance *t = *((JSInstance **)pc);
pc += sizeof(JSInstance *);
pushValue(JSValue(t));
}
break;
@ -844,11 +842,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
case DeleteOp:
{
JSValue base = popValue();
JSObject *obj = NULL;
if (!base.isObject() && !base.isType())
obj = base.toObject(this).object;
else
obj = base.object;
JSObject *obj = base.toObjectValue(this);
uint32 index = *((uint32 *)pc);
pc += sizeof(uint32);
const StringAtom &name = *mCurModule->getString(index);
@ -891,8 +885,8 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
JSValue t = popValue();
JSValue v = popValue();
if (t.isType()) {
if (v.isObject()
&& (v.object->getType() == t.type))
if (v.isInstance()
&& (v.instance->getType() == t.type))
pushValue(v);
else
pushValue(kNullValue); // XXX or throw an exception if
@ -913,9 +907,9 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
else
pushValue(kFalseValue);
else
if (v.isObject()
&& ((v.object->getType() == t.type)
|| (v.object->getType()->derivesFrom(t.type))))
if (v.isInstance()
&& ((v.instance->getType() == t.type)
|| (v.instance->getType()->derivesFrom(t.type))))
pushValue(kTrueValue);
else {
if (v.getType() == t.type)
@ -978,9 +972,9 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
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))));
pushValue(JSValue((JSFunction *)(new JSBoundFunction(this, result.function, NULL))));
else
pushValue(JSValue((JSFunction *)(new JSBoundFunction(result.function, parent))));
pushValue(JSValue((JSFunction *)(new JSBoundFunction(this, result.function, parent))));
}
if (useOnceNamespace) {
NamespaceList *t = mNamespaceList->mNext;
@ -1033,29 +1027,18 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
pc += sizeof(uint16);
mPC = pc;
JSValue *baseValue = getBase(stackSize() - (dimCount + 1));
JSValue *base = getBase(stackSize() - (dimCount + 1));
// 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())
obj = baseValue->object;
else
obj = baseValue->toObject(this).object;
JSFunction *target = obj->getType()->getUnaryOperator(Index);
JSObject *obj = base->toObjectValue(this);
JSFunction *target = getUnaryOperator(base->getType(), Index);
if (target) {
JSValue result;
if (target->isNative()) {
JSValue *argBase = new JSValue[dimCount + 1];
for (uint32 i = 0; i < (dimCount + 1); i++)
argBase[i] = baseValue[i];
argBase[i] = base[i];
resizeStack(stackSize() - (dimCount + 1));
result = target->getNativeCode()(this, argBase[0], argBase, dimCount + 1);
delete[] argBase;
@ -1090,9 +1073,9 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
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))));
pushValue(JSValue((JSFunction *)(new JSBoundFunction(this, result.function, NULL))));
else
pushValue(JSValue((JSFunction *)(new JSBoundFunction(result.function, obj))));
pushValue(JSValue((JSFunction *)(new JSBoundFunction(this, result.function, obj))));
}
}
break;
@ -1102,15 +1085,11 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
pc += sizeof(uint16);
mPC = pc;
JSValue *baseValue = getBase(stackSize() - (dimCount + 2)); // +1 for assigned value
JSValue *base = getBase(stackSize() - (dimCount + 2)); // +1 for assigned value
// Use the type of the base to dispatch on...
JSObject *obj = NULL;
if (!baseValue->isObject() && !baseValue->isType())
obj = baseValue->toObject(this).object;
else
obj = baseValue->object;
JSFunction *target = obj->getType()->getUnaryOperator(IndexEqual);
JSObject *obj = base->toObjectValue(this);
JSFunction *target = getUnaryOperator(base->getType(), IndexEqual);
if (target) {
JSValue v = popValue(); // need to have this sitting right above the base value
@ -1123,9 +1102,9 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
if (target->isNative()) {
JSValue *argBase = new JSValue[dimCount + 2];
for (uint32 i = 0; i < (dimCount + 2); i++)
argBase[i] = baseValue[i];
argBase[i] = base[i];
resizeStack(stackSize() - (dimCount + 2));
result = target->getNativeCode()(this, *baseValue, baseValue, (dimCount + 2));
result = target->getNativeCode()(this, *base, base, (dimCount + 2));
delete[] argBase;
}
else {
@ -1133,7 +1112,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
JSValue *argBase = buildArgumentBlock(target, argCount);
resizeStack(stackSize() - (dimCount + 2));
try {
result = interpret(target->getByteCode(), 0, target->getScopeChain(), *baseValue, argBase, argCount);
result = interpret(target->getByteCode(), 0, target->getScopeChain(), *base, argBase, argCount);
}
catch (Exception &x) {
delete[] argBase;
@ -1163,22 +1142,18 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
pc += sizeof(uint16);
mPC = pc;
JSValue *baseValue = getBase(stackSize() - (dimCount + 1));
JSValue *base = getBase(stackSize() - (dimCount + 1));
// Use the type of the base to dispatch on...
JSObject *obj = NULL;
if (!baseValue->isObject() && !baseValue->isType())
obj = baseValue->toObject(this).object;
else
obj = baseValue->object;
JSFunction *target = obj->getType()->getUnaryOperator(DeleteIndex);
JSObject *obj = base->toObjectValue(this);
JSFunction *target = getUnaryOperator(base->getType(), DeleteIndex);
if (target) {
JSValue result;
if (target->isNative()) {
JSValue *argBase = new JSValue[dimCount + 1];
for (uint32 i = 0; i < (dimCount + 1); i++)
argBase[i] = baseValue[i];
argBase[i] = base[i];
resizeStack(stackSize() - (dimCount + 1));
result = target->getNativeCode()(this, argBase[0], argBase, dimCount + 1);
delete[] argBase;
@ -1213,11 +1188,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
case GetPropertyOp:
{
JSValue base = popValue();
JSObject *obj = NULL;
if (!base.isObject() && !base.isType())
obj = base.toObject(this).object;
else
obj = base.object;
JSObject *obj = base.toObjectValue(this);
uint32 index = *((uint32 *)pc);
pc += sizeof(uint32);
mPC = pc;
@ -1231,9 +1202,9 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
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))));
pushValue(JSValue((JSFunction *)(new JSBoundFunction(this, result.function, NULL))));
else
pushValue(JSValue((JSFunction *)(new JSBoundFunction(result.function, obj))));
pushValue(JSValue((JSFunction *)(new JSBoundFunction(this, result.function, obj))));
}
if (useOnceNamespace) {
NamespaceList *t = mNamespaceList->mNext;
@ -1246,21 +1217,17 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
case GetInvokePropertyOp:
{
JSValue base = topValue();
JSObject *obj = NULL;
if (!base.isObject() && !base.isType() && !base.isFunction()) {
obj = base.toObject(this).object;
popValue();
pushValue(JSValue(obj)); // want the "toObject'd" version of base
}
else
obj = base.object;
JSValue baseObject = base.toObject(this);
// XXX really only need to pop/push if the base got modified
popValue();
pushValue(baseObject); // want the "toObject'd" version of base
uint32 index = *((uint32 *)pc);
pc += sizeof(uint32);
mPC = pc;
const StringAtom &name = *mCurModule->getString(index);
obj->getProperty(this, name, mNamespaceList);
baseObject.getObjectValue()->getProperty(this, name, mNamespaceList);
if (useOnceNamespace) {
NamespaceList *t = mNamespaceList->mNext;
delete mNamespaceList;
@ -1276,11 +1243,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
v = JSValue(v.function->getFunction());
}
JSValue base = popValue();
JSObject *obj = NULL;
if (!base.isObject() && !base.isType())
obj = base.toObject(this).object;
else
obj = base.object;
JSObject *obj = base.toObjectValue(this);
uint32 index = *((uint32 *)pc);
pc += sizeof(uint32);
mPC = pc;
@ -1300,9 +1263,8 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
Operator op = (Operator)(*pc++);
mPC = pc;
JSValue v = topValue();
JSFunction *target;
if (v.isObject() && (target = v.object->getType()->getUnaryOperator(op)) )
{
JSFunction *target = getUnaryOperator(v.getType(), op);
if (target) {
uint32 argBase = stackSize() - 1;
JSValue newThis = kNullValue;
if (!target->isNative()) {
@ -1404,7 +1366,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
PropertyIterator i;
if (target->hasProperty(this, Prototype_StringAtom, mNamespaceList, Read, &i)) {
JSValue v = target->getPropertyValue(i);
newThis.object->mPrototype = v.toObject(this).object;
newThis.object->mPrototype = v.toObjectValue(this);
newThis.object->setProperty(this, UnderbarPrototype_StringAtom, (NamespaceList *)NULL, JSValue(newThis.object->mPrototype));
}
}
@ -1415,9 +1377,9 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
// if the type has an operator "new" use that,
// otherwise use the default constructor (and pass NULL
// for the this value)
target = typeValue->type->getUnaryOperator(New);
target = getUnaryOperator(typeValue->type, New);
if (target)
newThis = JSValue(typeValue->type->newInstance(this));
newThis = typeValue->type->newInstance(this);
else {
newThis = kNullValue;
target = typeValue->type->getDefaultConstructor();
@ -1437,10 +1399,10 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
argBase = buildArgumentBlock(target, argCount);
resizeStack(stackSize() - cleanUp);
if (!target->isChecked()) {
JSArrayInstance *args = (JSArrayInstance *)Array_Type->newInstance(this);
JSValue args = Array_Type->newInstance(this);
for (uint32 i = 0; i < argCount; i++)
args->setProperty(this, *numberToString(i), NULL, argBase[i]);
target->getActivation()->setProperty(this, Arguments_StringAtom, NULL, JSValue(args));
args.instance->setProperty(this, *numberToString(i), NULL, argBase[i]);
target->getActivation()->setProperty(this, Arguments_StringAtom, NULL, args);
}
try {
result = interpret(target->getByteCode(), 0, target->getScopeChain(), newThis, argBase, argCount);
@ -1471,13 +1433,13 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
JSValue v = popValue();
if (mThis.isNull()) {
ASSERT(v.isType());
mThis = JSValue(v.type->newInstance(this));
mThis = v.type->newInstance(this);
}
}
break;
case NewObjectOp:
{
pushValue(JSValue(Object_Type->newInstance(this)));
pushValue(Object_Type->newInstance(this));
}
break;
case GetLocalVarOp:
@ -1550,28 +1512,29 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
case GetMethodOp:
{
JSValue base = topValue();
ASSERT(dynamic_cast<JSInstance *>(base.object));
ASSERT(base.isInstance());
uint32 index = *((uint32 *)pc);
pc += sizeof(uint32);
pushValue(JSValue(base.object->mType->mMethods[index]));
pushValue(JSValue(base.instance->mType->mMethods[index]));
}
break;
case GetMethodRefOp:
{
JSValue base = popValue();
ASSERT(dynamic_cast<JSInstance *>(base.object));
if (!base.isInstance())
reportError(Exception::semanticError, "Illegal method reference");
uint32 index = *((uint32 *)pc);
pc += sizeof(uint32);
pushValue(JSValue(new JSBoundFunction(base.object->mType->mMethods[index], base.object)));
pushValue(JSValue(new JSBoundFunction(this, base.instance->mType->mMethods[index], base.object)));
}
break;
case GetFieldOp:
{
JSValue base = popValue();
ASSERT(dynamic_cast<JSInstance *>(base.object));
ASSERT(base.isInstance());
uint32 index = *((uint32 *)pc);
pc += sizeof(uint32);
pushValue(((JSInstance *)(base.object))->mInstanceValues[index]);
pushValue(base.instance->mInstanceValues[index]);
}
break;
case SetFieldOp:
@ -1581,17 +1544,17 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
v = JSValue(v.function->getFunction());
}
JSValue base = popValue();
ASSERT(dynamic_cast<JSInstance *>(base.object));
ASSERT(base.isInstance());
uint32 index = *((uint32 *)pc);
pc += sizeof(uint32);
((JSInstance *)(base.object))->mInstanceValues[index] = v;
base.instance->mInstanceValues[index] = v;
pushValue(v);
}
break;
case WithinOp:
{
JSValue base = popValue();
mScopeChain->addScope(base.toObject(this).object);
mScopeChain->addScope(base.toObjectValue(this));
}
break;
case WithoutOp:
@ -1660,11 +1623,11 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
JSValue v2 = popValue();
JSValue v1 = popValue();
ASSERT(v1.isObject() && (v1.object->getType() == Attribute_Type));
ASSERT(v2.isObject() && (v2.object->getType() == Attribute_Type));
ASSERT(v1.isAttribute());
ASSERT(v2.isAttribute());
Attribute *a1 = static_cast<Attribute *>(v1.object);
Attribute *a2 = static_cast<Attribute *>(v2.object);
Attribute *a1 = v1.attribute;
Attribute *a2 = v2.attribute;
if ((a1->mTrueFlags & a2->mFalseFlags) != 0)
reportError(Exception::semanticError, "Mismatched attributes"); // XXX could supply more detail
@ -1796,40 +1759,73 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
return result;
}
// called on a JSValue to return a base object. The value may be a type, function, instance
// or generic object
JSObject *JSValue::getObjectValue() const
{
switch (tag) {
case object_tag:
return object;
case instance_tag:
return instance;
case function_tag:
return function;
case type_tag:
return type;
case package_tag:
return package;
default:
NOT_REACHED("Bad tag");
return NULL;
}
}
// called on a JSValue with type == Number_Type, which could be either a tagged
// value or a Number object (actually an instance). Return the raw value in either case.
float64 JSValue::getNumberValue() const
{
if (isNumber())
return f64;
ASSERT(isObject() && (getType() == Number_Type));
return *((float64 *)(object->mPrivate));
ASSERT(isInstance() && (getType() == Number_Type));
JSNumberInstance *numInst = checked_cast<JSNumberInstance *>(instance);
return numInst->mValue;
}
// called on a JSValue with type == String_Type, which could be either a tagged
// value or a String object (actually an instance). Return the raw value in either case.
const String *JSValue::getStringValue() const
{
if (isString())
return string;
ASSERT(isObject() && (getType() == String_Type));
return (const String *)(object->mPrivate);
ASSERT(isInstance() && (getType() == String_Type));
JSStringInstance *strInst = checked_cast<JSStringInstance *>(instance);
return strInst->mValue;
}
// called on a JSValue with type == Boolean_Type, which could be either a tagged
// value or a Boolean object (actually an instance). Return the raw value in either case.
bool JSValue::getBoolValue() const
{
if (isBool())
return boolean;
ASSERT(isObject() && (getType() == Boolean_Type));
return (object->mPrivate != 0);
ASSERT(isInstance() && (getType() == Boolean_Type));
JSBooleanInstance *boolInst = checked_cast<JSBooleanInstance *>(instance);
return boolInst->mValue;
}
// Implementation of '+' for two number types
static JSValue numberPlus(Context *, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
{
return JSValue(argv[0].getNumberValue() + argv[1].getNumberValue());
}
// Implementation of '+' for two integer types
static JSValue integerPlus(Context * /*cx*/, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
{
return JSValue(argv[0].getNumberValue() + argv[1].getNumberValue());
}
// Implementation of '+' for two 'generic' objects
static JSValue objectPlus(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
{
JSValue &r1 = argv[0];
@ -1873,16 +1869,19 @@ static JSValue objectPlus(Context *cx, const JSValue& /*thisValue*/, JSValue *ar
// Implementation of '-' for two integer types
static JSValue integerMinus(Context * /*cx*/, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
{
return JSValue(argv[0].getNumberValue() - argv[1].getNumberValue());
}
// Implementation of '-' for two number types
static JSValue numberMinus(Context *, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
{
return JSValue(argv[0].getNumberValue() - argv[1].getNumberValue());
}
// Implementation of '-' for two 'generic' objects
static JSValue objectMinus(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
{
JSValue &r1 = argv[0];
@ -1892,11 +1891,13 @@ static JSValue objectMinus(Context *cx, const JSValue& /*thisValue*/, JSValue *a
// Implementation of '*' for two integer types
static JSValue integerMultiply(Context * /*cx*/, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
{
return JSValue(argv[0].getNumberValue() * argv[1].getNumberValue());
}
// Implementation of '*' for two 'generic' objects
static JSValue objectMultiply(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
{
JSValue &r1 = argv[0];
@ -1905,7 +1906,7 @@ static JSValue objectMultiply(Context *cx, const JSValue& /*thisValue*/, JSValue
}
// Implementation of '/' for two integer types
static JSValue integerDivide(Context * /*cx*/, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
{
float64 f1 = argv[0].getNumberValue();
@ -1917,6 +1918,7 @@ static JSValue integerDivide(Context * /*cx*/, const JSValue& /*thisValue*/, JSV
return JSValue(d);
}
// Implementation of '/' for two 'generic' objects
static JSValue objectDivide(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
{
JSValue &r1 = argv[0];
@ -1925,7 +1927,7 @@ static JSValue objectDivide(Context *cx, const JSValue& /*thisValue*/, JSValue *
}
// Implementation of '%' for two integer types
static JSValue integerRemainder(Context * /*cx*/, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
{
float64 f1 = argv[0].getNumberValue();
@ -1937,6 +1939,7 @@ static JSValue integerRemainder(Context * /*cx*/, const JSValue& /*thisValue*/,
return JSValue(d);
}
// Implementation of '%' for two 'generic' objects
static JSValue objectRemainder(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
{
JSValue &r1 = argv[0];
@ -1955,7 +1958,7 @@ static JSValue objectRemainder(Context *cx, const JSValue& /*thisValue*/, JSValu
}
// Implementation of '<<' for two integer types
static JSValue integerShiftLeft(Context * /*cx*/, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
{
float64 f1 = argv[0].getNumberValue();
@ -1963,6 +1966,7 @@ static JSValue integerShiftLeft(Context * /*cx*/, const JSValue& /*thisValue*/,
return JSValue((float64)( (int32)(f1) << ( (uint32)(f2) & 0x1F)) );
}
// Implementation of '<<' for two 'generic' objects
static JSValue objectShiftLeft(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
{
JSValue &r1 = argv[0];
@ -1972,6 +1976,7 @@ static JSValue objectShiftLeft(Context *cx, const JSValue& /*thisValue*/, JSValu
// Implementation of '>>' for two integer types
static JSValue integerShiftRight(Context * /*cx*/, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
{
float64 f1 = argv[0].getNumberValue();
@ -1979,6 +1984,7 @@ static JSValue integerShiftRight(Context * /*cx*/, const JSValue& /*thisValue*/,
return JSValue((float64) ( (int32)(f1) >> ( (uint32)(f2) & 0x1F)) );
}
// Implementation of '>>' for two 'generic' objects
static JSValue objectShiftRight(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
{
JSValue &r1 = argv[0];
@ -1988,6 +1994,7 @@ static JSValue objectShiftRight(Context *cx, const JSValue& /*thisValue*/, JSVal
// Implementation of '>>>' for two integer types
static JSValue integerUShiftRight(Context * /*cx*/, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
{
float64 f1 = argv[0].getNumberValue();
@ -1995,6 +2002,7 @@ static JSValue integerUShiftRight(Context * /*cx*/, const JSValue& /*thisValue*/
return JSValue((float64) ( (uint32)(f1) >> ( (uint32)(f2) & 0x1F)) );
}
// Implementation of '>>>' for two 'generic' objects
static JSValue objectUShiftRight(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
{
JSValue &r1 = argv[0];
@ -2003,7 +2011,7 @@ static JSValue objectUShiftRight(Context *cx, const JSValue& /*thisValue*/, JSVa
}
// Implementation of '&' for two integer types
static JSValue integerBitAnd(Context * /*cx*/, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
{
float64 f1 = argv[0].getNumberValue();
@ -2011,6 +2019,7 @@ static JSValue integerBitAnd(Context * /*cx*/, const JSValue& /*thisValue*/, JSV
return JSValue((float64)( (int32)(f1) & (int32)(f2) ));
}
// Implementation of '&' for two 'generic' objects
static JSValue objectBitAnd(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
{
JSValue &r1 = argv[0];
@ -2020,6 +2029,7 @@ static JSValue objectBitAnd(Context *cx, const JSValue& /*thisValue*/, JSValue *
// Implementation of '^' for two integer types
static JSValue integerBitXor(Context * /*cx*/, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
{
float64 f1 = argv[0].getNumberValue();
@ -2027,6 +2037,7 @@ static JSValue integerBitXor(Context * /*cx*/, const JSValue& /*thisValue*/, JSV
return JSValue((float64)( (int32)(f1) ^ (int32)(f2) ));
}
// Implementation of '^' for two 'generic' objects
static JSValue objectBitXor(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
{
JSValue &r1 = argv[0];
@ -2036,6 +2047,7 @@ static JSValue objectBitXor(Context *cx, const JSValue& /*thisValue*/, JSValue *
// Implementation of '|' for two integer types
static JSValue integerBitOr(Context * /*cx*/, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
{
float64 f1 = argv[0].getNumberValue();
@ -2043,6 +2055,7 @@ static JSValue integerBitOr(Context * /*cx*/, const JSValue& /*thisValue*/, JSVa
return JSValue((float64)( (int32)(f1) | (int32)(f2) ));
}
// Implementation of '|' for two 'generic' objects
static JSValue objectBitOr(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/)
{
JSValue &r1 = argv[0];
@ -2095,6 +2108,7 @@ static JSValue objectLessEqual(Context *cx, const JSValue& /*thisValue*/, JSValu
return kTrueValue;
}
// Compare two values for '=='
static JSValue compareEqual(Context *cx, JSValue r1, JSValue r2)
{
JSType *t1 = r1.getType();
@ -2124,8 +2138,12 @@ static JSValue compareEqual(Context *cx, JSValue r1, JSValue r2)
return kTrueValue;
if (r1.isNull())
return kTrueValue;
if (r1.isObject() && r2.isObject()) // because new Boolean()->getType() == Boolean_Type
if (r1.isInstance() && r2.isInstance()) // because new Boolean()->getType() == Boolean_Type
return JSValue(r1.instance == r2.instance);
if (r1.isObject() && r2.isObject())
return JSValue(r1.object == r2.object);
if (r1.isPackage() && r2.isPackage())
return JSValue(r1.package == r2.package);
if (r1.isType())
return JSValue(r1.type == r2.type);
if (r1.isFunction())
@ -2206,7 +2224,7 @@ static JSValue objectSpittingImage(Context * /*cx*/, const JSValue& /*thisValue*
}
// Build the default state of the binary operator table
void Context::initOperators()
{
struct OpTableEntry {
@ -2263,72 +2281,106 @@ void Context::initOperators()
for (uint32 i = 0; i < sizeof(OpTable) / sizeof(OpTableEntry); i++) {
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);
mBinaryOperatorTable[OpTable[i].which].push_back(op);
}
}
// Convert a primitive value into an object value, this is a no-op for
// values that are already object-like.
// XXX for Waldemar - is it possible to modify behaviour for Number, Boolean etc
// so that the behaviour here of constructing a new instance of those types would
// be different?
JSValue JSValue::valueToObject(Context *cx, const JSValue& value)
{
switch (value.tag) {
case f64_tag:
{
JSObject *obj = Number_Type->newInstance(cx);
JSFunction *defCon = Number_Type->getDefaultConstructor();
JSValue argv[1];
JSValue thisValue = JSValue(obj);
argv[0] = value;
if (defCon->isNative()) {
(defCon->getNativeCode())(cx, thisValue, &argv[0], 1);
}
else {
ASSERT(false); // need to throw a hot potato back to
// ye interpreter loop
}
return thisValue;
JSValue result = Number_Type->newInstance(cx);
((JSNumberInstance *)result.instance)->mValue = value.f64;
return JSValue(result);
}
case boolean_tag:
{
JSObject *obj = Boolean_Type->newInstance(cx);
JSFunction *defCon = Boolean_Type->getDefaultConstructor();
JSValue argv[1];
JSValue thisValue = JSValue(obj);
argv[0] = value;
if (defCon->isNative()) {
(defCon->getNativeCode())(cx, thisValue, &argv[0], 1);
}
else {
ASSERT(false);
}
return thisValue;
JSValue result = Boolean_Type->newInstance(cx);
((JSBooleanInstance *)result.instance)->mValue = value.boolean;
return JSValue(result);
}
case string_tag:
{
JSObject *obj = String_Type->newInstance(cx);
JSFunction *defCon = String_Type->getDefaultConstructor();
JSValue argv[1];
JSValue thisValue = JSValue(obj);
argv[0] = value;
if (defCon->isNative()) {
(defCon->getNativeCode())(cx, thisValue, &argv[0], 1);
}
else {
ASSERT(false);
}
return thisValue;
JSValue result = String_Type->newInstance(cx);
((JSStringInstance *)result.instance)->mValue = value.string;
return JSValue(result);
}
case instance_tag:
case package_tag:
case type_tag:
case object_tag:
case function_tag:
return value;
case null_tag:
cx->reportError(Exception::typeError, "converting null to object");
case undefined_tag:
cx->reportError(Exception::typeError, "ToObject");
cx->reportError(Exception::typeError, "converting undefined to object");
default:
NOT_REACHED("Bad tag");
return kUndefinedValue;
}
}
// Convert a value to an object, without constructing a new value
// unless absolutely necessary, which would be the case for using
// valueToObject().getObjectValue() instead.
// XXX for Waldemar - is it possible to modify behaviour for Number, Boolean etc
// so that the behaviour here of constructing a new instance of those types would
// be different?
JSObject *JSValue::toObjectValue(Context *cx) const
{
switch (tag) {
case f64_tag:
{
JSValue result = Number_Type->newInstance(cx);
((JSNumberInstance *)result.instance)->mValue = f64;
return result.instance;
}
case boolean_tag:
{
JSValue result = Boolean_Type->newInstance(cx);
((JSBooleanInstance *)result.instance)->mValue = boolean;
return result.instance;
}
case string_tag:
{
JSValue result = String_Type->newInstance(cx);
((JSStringInstance *)result.instance)->mValue = string;
return result.instance;
}
case type_tag:
return type;
case object_tag:
return object;
case function_tag:
return function;
case instance_tag:
return instance;
case package_tag:
return package;
case null_tag:
cx->reportError(Exception::typeError, "converting null to object");
case undefined_tag:
cx->reportError(Exception::typeError, "converting undefined to object");
default:
NOT_REACHED("Bad tag");
return NULL;
}
}
// convert string to double - a wrapper around the numerics routine
// to handle hex literals as well
float64 stringToNumber(const String *string)
{
const char16 *numEnd;
@ -2353,6 +2405,7 @@ float64 stringToNumber(const String *string)
return 0.0;
}
// Convert a JSValue to number-type
JSValue JSValue::valueToNumber(Context *cx, const JSValue& value)
{
switch (value.tag) {
@ -2361,6 +2414,9 @@ JSValue JSValue::valueToNumber(Context *cx, const JSValue& value)
case string_tag:
return JSValue(stringToNumber(value.string));
case object_tag:
case instance_tag:
case package_tag:
case type_tag:
case function_tag:
return value.toPrimitive(cx, NumberHint).toNumber(cx);
case boolean_tag:
@ -2375,6 +2431,7 @@ JSValue JSValue::valueToNumber(Context *cx, const JSValue& value)
}
}
// Convert a double to a string representation (base-10)
const String *numberToString(float64 number)
{
char buf[dtosStandardBufferSize];
@ -2382,6 +2439,7 @@ const String *numberToString(float64 number)
return new JavaScript::String(widenCString(chrp));
}
// Convert a JSValue to a string (ECMA rules)
JSValue JSValue::valueToString(Context *cx, const JSValue& value)
{
const String *strp = NULL;
@ -2409,6 +2467,12 @@ JSValue JSValue::valueToString(Context *cx, const JSValue& value)
case null_tag:
strp = &cx->Null_StringAtom;
break;
case instance_tag:
obj = value.instance;
break;
case package_tag:
obj = value.package;
break;
default:
NOT_REACHED("Bad tag");
}
@ -2437,6 +2501,7 @@ JSValue JSValue::valueToString(Context *cx, const JSValue& value)
}
// Convert a JSValue to a primitive type
JSValue JSValue::toPrimitive(Context *cx, Hint hint) const
{
JSObject *obj;
@ -2447,10 +2512,13 @@ JSValue JSValue::toPrimitive(Context *cx, Hint hint) const
case undefined_tag:
return *this;
case instance_tag:
obj = instance;
if ((hint == NoHint) && (getType() == Date_Type))
hint = StringHint;
break;
case object_tag:
obj = object;
if ((hint == NoHint) && (obj->getType() == Date_Type))
hint = StringHint;
break;
case function_tag:
obj = function;
@ -2658,6 +2726,8 @@ JSValue JSValue::valueToBoolean(Context * /*cx*/, const JSValue& value)
return JSValue(value.string->length() != 0);
case boolean_tag:
return value;
case type_tag:
case instance_tag:
case object_tag:
case function_tag:
return kTrueValue;
@ -2715,7 +2785,8 @@ JSType *JSValue::getType() const {
case f64_tag: return Number_Type;
case boolean_tag: return Boolean_Type;
case string_tag: return (JSType *)String_Type;
case object_tag: return object->getType();
case object_tag: return Object_Type;
case instance_tag: return instance->getType();
case undefined_tag: return Void_Type;
case null_tag: return Null_Type;
case function_tag: return Function_Type;
@ -2727,6 +2798,32 @@ JSType *JSValue::getType() const {
}
JSFunction *Context::getUnaryOperator(JSType *dispatchType, Operator which)
{
// look in the operator table for applicable operators
OperatorList applicableOperators;
for (OperatorList::iterator oi = mUnaryOperatorTable[which].begin(),
end = mUnaryOperatorTable[which].end();
(oi != end); oi++) {
if ((*oi)->isApplicable(dispatchType)) {
applicableOperators.push_back(*oi);
}
}
if (applicableOperators.size() == 0)
return NULL;
OperatorList::iterator candidate = applicableOperators.begin();
for (OperatorList::iterator aoi = applicableOperators.begin() + 1,
aend = applicableOperators.end();
(aoi != aend); aoi++)
{
if ((*aoi)->mType1->derivesFrom((*candidate)->mType1) )
candidate = aoi;
}
return (*candidate)->mImp;
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -50,6 +50,7 @@
#include "tracer.h"
#include "collector.h"
#include "regexp.h"
namespace JavaScript {
namespace JS2Runtime {
@ -99,6 +100,10 @@ static const double two31 = 2147483648.0;
class JSArrayType;
class JSStringType;
class Context;
class NamedArgument;
class JSInstance;
class Attribute;
class Package;
extern JSType *Object_Type; // the base type for all types
@ -117,7 +122,6 @@ static const double two31 = 2147483648.0;
extern JSType *Attribute_Type; // used to define 'prototype' 'static' etc & Namespace values
extern JSType *Package_Type;
extern JSType *NamedArgument_Type;
extern JSType *Date_Type;
extern JSType *RegExp_Type;
@ -132,46 +136,63 @@ static const double two31 = 2147483648.0;
union {
float64 f64;
JSObject *object;
JSInstance *instance;
JSFunction *function;
const String *string;
JSType *type;
bool boolean;
NamedArgument *namedArg;
Attribute *attribute;
Package *package;
};
typedef enum {
undefined_tag,
f64_tag,
object_tag,
instance_tag,
function_tag,
type_tag,
boolean_tag,
string_tag,
null_tag
null_tag,
namedArg_tag,
attribute_tag,
package_tag
} Tag;
Tag tag;
JSValue() : f64(0.0), tag(undefined_tag) {}
explicit JSValue(float64 f64) : f64(f64), tag(f64_tag) {}
explicit JSValue(JSObject *object) : object(object), tag(object_tag) { ASSERT(object); }
explicit JSValue(JSInstance *instance) : instance(instance), tag(instance_tag) { ASSERT(instance); }
explicit JSValue(JSFunction *function) : function(function), tag(function_tag) { ASSERT(function); }
explicit JSValue(JSType *type) : type(type), tag(type_tag) { ASSERT(type); }
explicit JSValue(const String *string) : string(string), tag(string_tag) { ASSERT(string); }
explicit JSValue(bool boolean) : boolean(boolean), tag(boolean_tag) {}
explicit JSValue(NamedArgument *arg) : namedArg(arg), tag(namedArg_tag) { ASSERT(arg); }
explicit JSValue(Attribute *attr) : attribute(attr), tag(attribute_tag) { ASSERT(attribute); }
explicit JSValue(Package *pkg) : package(pkg), tag(package_tag) { ASSERT(pkg); }
explicit JSValue(Tag tag) : tag(tag) {}
float64& operator=(float64 f64) { return (tag = f64_tag, this->f64 = f64); }
JSObject*& operator=(JSObject* object) { return (tag = object_tag, this->object = object); }
JSInstance*& operator=(JSInstance* instance) { return (tag = instance_tag, this->instance = instance); }
JSType*& operator=(JSType* type) { return (tag = type_tag, this->type = type); }
JSFunction*& operator=(JSFunction* function) { return (tag = function_tag, this->function = function); }
bool& operator=(bool boolean) { return (tag = boolean_tag, this->boolean = boolean); }
bool isObject() const { return (tag == object_tag); }
bool isInstance() const { return (tag == instance_tag); }
bool isNumber() const { return (tag == f64_tag); }
bool isBool() const { return (tag == boolean_tag); }
bool isType() const { return (tag == type_tag); }
bool isFunction() const { return (tag == function_tag); }
bool isString() const { return (tag == string_tag); }
bool isPrimitive() const { return (tag != object_tag) && (tag != type_tag) && (tag != function_tag); }
bool isPrimitive() const { return isNumber() || isBool() || isString() || isUndefined() || isNull(); }
bool isNamedArg() const { return (tag == namedArg_tag); }
bool isAttribute() const { return (tag == attribute_tag); }
bool isPackage() const { return (tag == package_tag); }
bool isUndefined() const { return (tag == undefined_tag); }
bool isNull() const { return (tag == null_tag); }
@ -192,13 +213,16 @@ static const double two31 = 2147483648.0;
JSValue toUInt32(Context *cx) const { return valueToUInt32(cx, *this); }
JSValue toUInt16(Context *cx) const { return valueToUInt16(cx, *this); }
JSValue toInt32(Context *cx) const { return valueToInt32(cx, *this); }
JSValue toObject(Context *cx) const { return ((isObject() || isType() || isFunction()) ?
JSValue toObject(Context *cx) const { return ((isObject() || isType() || isFunction() || isInstance() || isPackage()) ?
*this : valueToObject(cx, *this)); }
JSValue toBoolean(Context *cx) const { return (isBool() ? *this : valueToBoolean(cx, *this)); }
float64 getNumberValue() const;
const String *getStringValue() const;
bool getBoolValue() const;
JSObject *getObjectValue() const;
JSObject *toObjectValue(Context *cx) const;
/* These are for use in 'toPrimitive' calls */
enum Hint {
@ -524,23 +548,15 @@ XXX ...couldn't get this to work...
class JSObject {
public:
// The generic Javascript object. Every JS2 object is one of these
JSObject(JSType *type = Object_Type) : mType(type), mPrivate(NULL), mPrototype(NULL) { }
JSObject() : mPrototype(kNullValue) { }
virtual ~JSObject() { } // keeping gcc happy
// every object has a type
JSType *mType;
// the property data is kept (or referenced from) here
PropertyMap mProperties;
// Every JSObject has a private part
void *mPrivate;
// Every JSObject (except the Ur-object) has a prototype
JSObject *mPrototype;
JSType *getType() const { return mType; }
JSValue mPrototype;
virtual bool isDynamic() { return true; }
@ -638,11 +654,8 @@ XXX ...couldn't get this to work...
*/
Collector::size_type scan(Collector* collector)
{
mType = (JSType*) collector->copy(mType);
// enumerate property map elements.
// what is mPrivate?
mPrivate = collector->copy(mPrivate);
mPrototype = (JSObject*) collector->copy(mPrototype);
// scan mPrototype.
return sizeof(JSObject);
}
@ -681,7 +694,7 @@ XXX ...couldn't get this to work...
public:
JSInstance(Context *cx, JSType *type)
: JSObject(type), mInstanceValues(NULL) { if (type) initInstance(cx, type); }
: JSObject(), mType(type), mInstanceValues(NULL) { if (type) initInstance(cx, type); }
virtual ~JSInstance() { } // keeping gcc happy
@ -700,8 +713,12 @@ XXX ...couldn't get this to work...
mInstanceValues[index] = v;
}
virtual bool isDynamic();
JSType *getType() const { return mType; }
bool isDynamic();
// the class that created this instance
JSType *mType;
JSValue *mInstanceValues;
@ -714,6 +731,7 @@ XXX ...couldn't get this to work...
Collector::size_type scan(Collector* collector)
{
JSObject::scan(collector);
mType = (JSType*) collector->copy(mType);
// FIXME: need some kind of array operator new[] (gc) thing.
// this will have to use an extra word to keep track of the
// element count.
@ -751,13 +769,20 @@ XXX ...couldn't get this to work...
class JSType : public JSObject {
class JSType : public JSInstance {
protected:
// XXX these initializations are for ParameterBarrel & Activation which are 'types' only
// because they take advantage of the slotted variable handling - maybe an interim class
// for just that purpose would be better...
JSType() : JSInstance(NULL, NULL), mSuperType(NULL), mIsDynamic(false), mVariableCount(0) { }
public:
JSType(Context *cx, const StringAtom *name, JSType *super, JSObject *protoObj = NULL, JSObject *typeProto = NULL);
JSType(JSType *xClass); // used for constructing the static component type
JSType(Context *cx, const StringAtom *name, JSType *super, JSValue &protoObj, JSValue &typeProto);
virtual ~JSType() { } // keeping gcc happy
void setSuperType(JSType *super);
void setStaticInitializer(Context *cx, JSFunction *f);
@ -767,7 +792,7 @@ XXX ...couldn't get this to work...
// construct a new (empty) instance of this class
virtual JSInstance *newInstance(Context *cx);
virtual JSValue newInstance(Context *cx);
Property *defineVariable(Context *cx, const String& name, AttributeStmtNode *attr, JSType *type);
@ -794,16 +819,6 @@ XXX ...couldn't get this to work...
void defineSetterMethod(Context *cx, const String &name, AttributeStmtNode *attr, JSFunction *f);
void defineUnaryOperator(Operator which, JSFunction *f)
{
mUnaryOperators[which] = f;
}
JSFunction *getUnaryOperator(Operator which)
{
return mUnaryOperators[which]; // XXX Umm, aren't these also getting inherited?
}
void setDefaultConstructor(Context * /*cx*/, JSFunction *f)
{
mDefaultConstructor = f;
@ -827,16 +842,17 @@ XXX ...couldn't get this to work...
JSFunction *getDefaultConstructor() { return mDefaultConstructor; }
JSFunction *getTypeCastFunction() { return mTypeCast; }
JSValue getUninitializedValue() { return mUninitializedValue; }
JSValue getUninitializedValue() { return mUninitializedValue; }
// Generates defaultConstructor if one doesn't exist -
// assumes that the super types have been completed already
void completeClass(Context *cx, ScopeChain *scopeChain);
virtual bool isDynamic() { return mIsDynamic; }
virtual bool isDynamic() { return mIsDynamic; }
JSType *mSuperType; // NULL implies that this is the base Object
JSType *mSuperType; // NULL implies that this is the base Object
uint32 mVariableCount;
uint32 mVariableCount; // number of instance variables
JSFunction *mInstanceInitializer;
JSFunction *mDefaultConstructor;
JSFunction *mTypeCast;
@ -847,14 +863,12 @@ XXX ...couldn't get this to work...
const StringAtom *mClassName;
const StringAtom *mPrivateNamespace;
JSFunction *mUnaryOperators[OperatorCount]; // XXX too wasteful
bool mIsDynamic;
JSValue mUninitializedValue; // the value for uninitialized vars
JSObject *mPrototypeObject; // becomes the prototype for any instance
JSValue mPrototypeObject; // becomes the prototype for any instance
// DEBUG
void printSlotsNStuff(Formatter& f) const;
protected:
@ -873,11 +887,8 @@ XXX ...couldn't get this to work...
// scan mMethods.
// scan mClassName.
// scan mPrivateNamespace.
uint32 i;
for (i = 0; i < OperatorCount; ++i)
mUnaryOperators[i] = (JSFunction*) collector->copy(mUnaryOperators[i]);
// scan mUninitializedValue.
mPrototypeObject = (JSObject*) collector->copy(mPrototypeObject);
// scan mPrototypeObject.
return sizeof(JSType);
}
@ -897,17 +908,27 @@ XXX ...couldn't get this to work...
Formatter& operator<<(Formatter& f, const JSType& obj);
//
// we have to have unique instance classes whenever the instance requires
// extra data - otherwise where else does this data go?
//
// XXX could instead have dynamically constructed the various classes with
// the appropriate number of instance slots and used the generic newInstance
// mechanism. Then the extra data would just be instance->slot[0,1...]
//
// XXX maybe could have implemented length (for string) as a getter/setter pair
// (would still require StringType, but the new instances would all get
// the pair of methods for free)
//
class JSArrayInstance : public JSInstance {
public:
JSArrayInstance(Context *cx, JSType * /*type*/) : JSInstance(cx, NULL), mLength(0) { mType = (JSType *)Array_Type; mPrototype = Object_Type->mPrototypeObject; }
JSArrayInstance(Context *cx) : JSInstance(cx, NULL), mLength(0) { mType = (JSType *)Array_Type; mPrototype = Object_Type->mPrototypeObject; }
virtual ~JSArrayInstance() { } // keeping gcc happy
#ifdef DEBUG
void* operator new(size_t s) { void *t = STD::malloc(s); trace_alloc("JSArrayInstance", s, t); return t; }
void operator delete(void* t) { trace_release("JSArrayInstance", t); STD::free(t); }
#endif
// XXX maybe could have implemented length as a getter/setter pair?
void setProperty(Context *cx, const String &name, NamespaceList *names, const JSValue &v);
void getProperty(Context *cx, const String &name, NamespaceList *names);
@ -915,12 +936,11 @@ XXX ...couldn't get this to work...
bool deleteProperty(Context *cx, const String &name, NamespaceList *names);
uint32 mLength;
};
class JSArrayType : public JSType {
public:
JSArrayType(Context *cx, JSType *elementType, const StringAtom *name, JSType *super, JSObject *protoObj = NULL, JSObject *typeProto = NULL)
JSArrayType(Context *cx, JSType *elementType, const StringAtom *name, JSType *super, JSValue &protoObj, JSValue &typeProto)
: JSType(cx, name, super, protoObj, typeProto), mElementType(elementType)
{
}
@ -931,51 +951,154 @@ XXX ...couldn't get this to work...
void operator delete(void* t) { trace_release("JSArrayType", t); STD::free(t); }
#endif
JSInstance *newInstance(Context *cx);
JSValue newInstance(Context *cx);
JSType *mElementType;
};
class JSStringInstance : public JSInstance {
public:
JSStringInstance(Context *cx, JSType * /*type*/) : JSInstance(cx, NULL), mLength(0) { mType = (JSType *)String_Type; }
JSStringInstance(Context *cx) : JSInstance(cx, NULL), mValue(NULL) { mType = (JSType *)String_Type; }
virtual ~JSStringInstance() { } // keeping gcc happy
#ifdef DEBUG
void* operator new(size_t s) { void *t = STD::malloc(s); trace_alloc("JSStringInstance", s, t); return t; }
void operator delete(void* t) { trace_release("JSStringInstance", t); STD::free(t); }
#endif
void setProperty(Context *cx, const String &name, NamespaceList *names, const JSValue &v);
void getProperty(Context *cx, const String &name, NamespaceList *names);
bool hasOwnProperty(Context *cx, const String &name, NamespaceList *names, Access acc, PropertyIterator *p);
bool deleteProperty(Context *cx, const String &name, NamespaceList *names);
uint32 mLength;
const String *mValue;
};
class JSStringType : public JSType {
public:
JSStringType(Context *cx, const StringAtom *name, JSType *super, JSObject *protoObj = NULL, JSObject *typeProto = NULL)
JSStringType(Context *cx, const StringAtom *name, JSType *super, JSValue &protoObj, JSValue &typeProto)
: JSType(cx, name, super, protoObj, typeProto)
{
}
virtual ~JSStringType() { } // keeping gcc happy
#ifdef DEBUG
void* operator new(size_t s) { void *t = STD::malloc(s); trace_alloc("JSStringType", s, t); return t; }
void operator delete(void* t) { trace_release("JSStringType", t); STD::free(t); }
#endif
JSInstance *newInstance(Context *cx);
JSValue newInstance(Context *cx);
};
class JSBooleanInstance : public JSInstance {
public:
JSBooleanInstance(Context *cx) : JSInstance(cx, NULL), mValue(false) { mType = (JSType *)Boolean_Type; }
virtual ~JSBooleanInstance() { } // keeping gcc happy
#ifdef DEBUG
void* operator new(size_t s) { void *t = STD::malloc(s); trace_alloc("JSBooleanInstance", s, t); return t; }
void operator delete(void* t) { trace_release("JSBooleanInstance", t); STD::free(t); }
#endif
bool mValue;
};
class JSBooleanType : public JSType {
public:
JSBooleanType(Context *cx, const StringAtom *name, JSType *super, JSValue &protoObj, JSValue &typeProto)
: JSType(cx, name, super, protoObj, typeProto)
{
}
virtual ~JSBooleanType() { } // keeping gcc happy
#ifdef DEBUG
void* operator new(size_t s) { void *t = STD::malloc(s); trace_alloc("JSBooleanType", s, t); return t; }
void operator delete(void* t) { trace_release("JSBooleanType", t); STD::free(t); }
#endif
JSValue newInstance(Context *cx);
};
class JSNumberInstance : public JSInstance {
public:
JSNumberInstance(Context *cx) : JSInstance(cx, NULL), mValue(0.0) { mType = (JSType *)Number_Type; }
virtual ~JSNumberInstance() { } // keeping gcc happy
#ifdef DEBUG
void* operator new(size_t s) { void *t = STD::malloc(s); trace_alloc("JSNumberInstance", s, t); return t; }
void operator delete(void* t) { trace_release("JSNumberInstance", t); STD::free(t); }
#endif
float64 mValue;
};
class JSNumberType : public JSType {
public:
JSNumberType(Context *cx, const StringAtom *name, JSType *super, JSValue &protoObj, JSValue &typeProto)
: JSType(cx, name, super, protoObj, typeProto)
{
}
virtual ~JSNumberType() { } // keeping gcc happy
#ifdef DEBUG
void* operator new(size_t s) { void *t = STD::malloc(s); trace_alloc("JSNumberType", s, t); return t; }
void operator delete(void* t) { trace_release("JSNumberType", t); STD::free(t); }
#endif
JSValue newInstance(Context *cx);
};
class JSDateInstance : public JSInstance {
public:
JSDateInstance(Context *cx) : JSInstance(cx, NULL), mValue(0.0) { mType = (JSType *)Date_Type; }
virtual ~JSDateInstance() { } // keeping gcc happy
#ifdef DEBUG
void* operator new(size_t s) { void *t = STD::malloc(s); trace_alloc("JSDateInstance", s, t); return t; }
void operator delete(void* t) { trace_release("JSDateInstance", t); STD::free(t); }
#endif
float64 mValue;
};
class JSDateType : public JSType {
public:
JSDateType(Context *cx, const StringAtom *name, JSType *super, JSValue &protoObj, JSValue &typeProto)
: JSType(cx, name, super, protoObj, typeProto)
{
}
virtual ~JSDateType() { } // keeping gcc happy
#ifdef DEBUG
void* operator new(size_t s) { void *t = STD::malloc(s); trace_alloc("JSDateType", s, t); return t; }
void operator delete(void* t) { trace_release("JSDateType", t); STD::free(t); }
#endif
JSValue newInstance(Context *cx);
};
class JSRegExpInstance : public JSInstance {
public:
JSRegExpInstance(Context *cx) : JSInstance(cx, NULL), mLastIndex(0), mRegExp(NULL) { mType = (JSType *)RegExp_Type; }
virtual ~JSRegExpInstance() { } // keeping gcc happy
#ifdef DEBUG
void* operator new(size_t s) { void *t = STD::malloc(s); trace_alloc("JSRegExpInstance", s, t); return t; }
void operator delete(void* t) { trace_release("JSRegExpInstance", t); STD::free(t); }
#endif
uint32 mLastIndex;
REState *mRegExp;
};
class JSRegExpType : public JSType {
public:
JSRegExpType(Context *cx, const StringAtom *name, JSType *super, JSValue &protoObj, JSValue &typeProto)
: JSType(cx, name, super, protoObj, typeProto)
{
}
virtual ~JSRegExpType() { } // keeping gcc happy
#ifdef DEBUG
void* operator new(size_t s) { void *t = STD::malloc(s); trace_alloc("JSBooleanType", s, t); return t; }
void operator delete(void* t) { trace_release("JSBooleanType", t); STD::free(t); }
#endif
JSValue newInstance(Context *cx);
};
class JSObjectType : public JSType {
public:
JSObjectType(Context *cx, const StringAtom *name, JSType *super, JSValue &protoObj, JSValue &typeProto)
: JSType(cx, name, super, protoObj, typeProto)
{
}
virtual ~JSObjectType() { } // keeping gcc happy
#ifdef DEBUG
void* operator new(size_t s) { void *t = STD::malloc(s); trace_alloc("JSObjectType", s, t); return t; }
void operator delete(void* t) { trace_release("JSObjectType", t); STD::free(t); }
#endif
JSValue newInstance(Context *cx);
};
// captures the Parameter names scope
@ -984,7 +1107,7 @@ XXX ...couldn't get this to work...
class ParameterBarrel : public JSType {
public:
ParameterBarrel() : JSType(NULL)
ParameterBarrel() : JSType()
{
}
virtual ~ParameterBarrel() { } // keeping gcc happy
@ -1020,8 +1143,7 @@ XXX ...couldn't get this to work...
public:
Activation()
: JSType(NULL),
mLocals(NULL),
: mLocals(NULL),
mStack(NULL),
mStackTop(0),
mPC(0),
@ -1037,8 +1159,7 @@ XXX ...couldn't get this to work...
uint8 *pc,
ByteCodeModule *module,
NamespaceList *namespaceList )
: JSType(NULL),
mLocals(locals),
: mLocals(locals),
mStack(stack),
mStackTop(stackTop),
mScopeChain(scopeChain),
@ -1186,12 +1307,7 @@ XXX ...couldn't get this to work...
ASSERT(dynamic_cast<JSType *>(top));
top->defineStaticSetterMethod(cx, name, attr, f);
}
void defineUnaryOperator(Operator which, JSFunction *f)
{
JSObject *top = mScopeStack.back();
ASSERT(dynamic_cast<JSType *>(top));
((JSType *)top)->defineUnaryOperator(which, f);
}
void defineUnaryOperator(Context *cx, Operator which, JSFunction *f);
// see if the current scope contains a name already
bool hasProperty(Context *cx, const String& name, NamespaceList *names, Access acc, PropertyIterator *p)
@ -1295,9 +1411,14 @@ XXX ...couldn't get this to work...
};
class JSFunction : public JSObject {
class JSFunction : public JSInstance {
protected:
JSFunction() : JSObject(Function_Type), mActivation() { mActivation.mContainer = this; mPrototype = Function_Type->mPrototypeObject; } // for JSBoundFunction (XXX ask Patrick about this structure)
JSFunction(Context *cx) : JSInstance(cx, NULL), mActivation()
{
mType = (JSType *)Function_Type;
mActivation.mContainer = this;
mPrototype = Function_Type->mPrototypeObject;
} // for JSBoundFunction (XXX ask Patrick about this structure)
public:
typedef enum { Invalid, RequiredParameter, OptionalParameter, RestParameter, NamedParameter } ParameterFlag;
@ -1421,7 +1542,7 @@ XXX ...couldn't get this to work...
mParameterBarrel = (ParameterBarrel*) collector->copy(mParameterBarrel);
mResultType = (JSType*) collector->copy(mResultType);
mClass = (JSType*) collector->copy(mClass);
mPrototype = (JSObject*) collector->copy(mPrototype);
// scan mPrototype.
return sizeof(JSFunction);
}
@ -1444,8 +1565,8 @@ XXX ...couldn't get this to work...
JSFunction *mFunction;
JSObject *mThis;
public:
JSBoundFunction(JSFunction *f, JSObject *thisObj)
: mFunction(NULL), mThis(thisObj) { if (f->hasBoundThis()) mFunction = f->getFunction(); else mFunction = f; }
JSBoundFunction(Context *cx, JSFunction *f, JSObject *thisObj)
: JSFunction(cx), mFunction(NULL), mThis(thisObj) { if (f->hasBoundThis()) mFunction = f->getFunction(); else mFunction = f; }
~JSBoundFunction() { } // keeping gcc happy
@ -1530,7 +1651,7 @@ XXX ...couldn't get this to work...
#endif
};
// This is for binary operators, it collects together the operand
// This is for unary & binary operators, it collects together the operand
// types and the function pointer for the given operand. See also
// Context::initOperators where the default operators are set up.
class OperatorDefinition {
@ -1539,6 +1660,8 @@ XXX ...couldn't get this to work...
OperatorDefinition(JSType *type1, JSType *type2, JSFunction *imp)
: mType1(type1), mType2(type2), mImp(imp) { ASSERT(mType1); ASSERT(mType2); }
OperatorDefinition(JSType *type1, JSFunction *imp)
: mType1(type1), mImp(imp) { ASSERT(mType1); }
JSType *mType1;
JSType *mType2;
@ -1553,13 +1676,15 @@ XXX ...couldn't get this to work...
((ty == mType2) || ty->derivesFrom(mType2)) );
}
bool isApplicable(JSType *tx)
{
return ( (tx == mType1) || tx->derivesFrom(mType1) );
}
};
// 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);
@ -1576,13 +1701,12 @@ XXX ...couldn't get this to work...
// called directly by String.match
extern JSValue RegExp_exec(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc);
class Attribute;
class Package : public JSObject {
class Package : public JSObject {
public:
typedef enum { OnItsWay, InHand } PackageStatus;
Package(const String &name) : JSObject(Package_Type), mName(name), mStatus(OnItsWay) { }
Package(const String &name) : JSObject(), mName(name), mStatus(OnItsWay) { }
String mName;
PackageStatus mStatus;
@ -1635,7 +1759,12 @@ XXX ...couldn't get this to work...
void* operator new(size_t s) { void *t = STD::malloc(s); trace_alloc("Context", s, t); return t; }
void operator delete(void* t) { trace_release("Context", t); STD::free(t); }
#endif
//
// Initialize a bunch of useful string atoms to save
// having to look them up during execution.
//
// Should these be in World instead?
//
StringAtom& Virtual_StringAtom;
StringAtom& Constructor_StringAtom;
StringAtom& Operator_StringAtom;
@ -1699,9 +1828,18 @@ XXX ...couldn't get this to work...
void defineOperator(Operator which, JSType *t1, JSType *t2, JSFunction *imp)
{
OperatorDefinition *op = new OperatorDefinition(t1, t2, imp);
mOperatorTable[which].push_back(op);
mBinaryOperatorTable[which].push_back(op);
}
void defineOperator(Operator which, JSType *t, JSFunction *imp)
{
OperatorDefinition *op = new OperatorDefinition(t, imp);
mUnaryOperatorTable[which].push_back(op);
}
// Construct an array of argument values, updating argCount to
// reflect the final size. Pulls incoming args from the top of
// the stack.
JSValue *buildArgumentBlock(JSFunction *target, uint32 &argCount);
@ -1711,10 +1849,11 @@ XXX ...couldn't get this to work...
Attribute *executeAttributes(ExprNode *attr);
// Run the binary operator designated, after using the types to do the dispatch
bool executeOperator(Operator op, JSType *t1, JSType *t2);
JSValue mapValueToType(JSValue v, JSType *t);
// Run the interpreter loop on the function
JSValue invokeFunction(JSFunction *target, const JSValue& thisValue, JSValue *argv, uint32 argc);
// This reader is used to generate source information
@ -1786,13 +1925,7 @@ XXX ...couldn't get this to work...
mStack[index] = v;
mStackTop++;
}
/*
void setValue(uint32 n, JSValue v)
{
ASSERT(n < mStackTop);
mStack[n] = v;
}
*/
JSValue *getBase(uint32 n)
{
ASSERT(n <= mStackTop); // s'ok to point beyond the end
@ -1825,7 +1958,9 @@ XXX ...couldn't get this to work...
typedef std::vector<OperatorDefinition *> OperatorList;
OperatorList mOperatorTable[OperatorCount];
// XXX bigger than necessary...
OperatorList mBinaryOperatorTable[OperatorCount];
OperatorList mUnaryOperatorTable[OperatorCount];
PackageList mPackages; // the currently loaded packages, mPackages.back() is the current package
@ -1848,6 +1983,8 @@ XXX ...couldn't get this to work...
void reportError(Exception::Kind kind, char *message, const String& name);
void reportError(Exception::Kind kind, char *message, size_t pos, const String& name);
JSFunction *getUnaryOperator(JSType *dispatchType, Operator which);
/* utility routines */
@ -1907,9 +2044,9 @@ XXX ...couldn't get this to work...
};
class NamedArgument : public JSObject {
class NamedArgument {
public:
NamedArgument(JSValue &v, const String *n) : JSObject(NamedArgument_Type), mValue(v), mName(n) { }
NamedArgument(JSValue &v, const String *n) : mValue(v), mName(n) { }
JSValue mValue;
const String *mName;
@ -1922,7 +2059,6 @@ XXX ...couldn't get this to work...
*/
Collector::size_type scan(Collector* collector)
{
JSObject::scan(collector);
mValue.scan(collector);
return sizeof(NamedArgument);
}
@ -1942,10 +2078,10 @@ XXX ...couldn't get this to work...
};
class Attribute : public JSObject {
class Attribute {
public:
Attribute(PropertyAttribute t, PropertyAttribute f)
: JSObject(Attribute_Type), mTrueFlags(t), mFalseFlags(f), mExtendArgument(NULL), mNamespaceList(NULL) { }
: mTrueFlags(t), mFalseFlags(f), mExtendArgument(NULL), mNamespaceList(NULL) { }
PropertyAttribute mTrueFlags;
PropertyAttribute mFalseFlags;
@ -1961,7 +2097,6 @@ XXX ...couldn't get this to work...
*/
Collector::size_type scan(Collector* collector)
{
JSObject::scan(collector);
mExtendArgument = (JSType*) collector->copy(mExtendArgument);
return sizeof(Attribute);
}
@ -2018,8 +2153,17 @@ XXX ...couldn't get this to work...
defineMethod(cx, name, attr, f);
}
inline bool JSInstance::isDynamic()
{
return mType->isDynamic();
}
inline bool JSInstance::isDynamic() { return mType->isDynamic(); }
inline void ScopeChain::defineUnaryOperator(Context *cx, Operator which, JSFunction *f)
{
JSObject *top = mScopeStack.back();
ASSERT(dynamic_cast<JSType *>(top));
cx->defineOperator(which, (JSType *)top, f);
}
}
}

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

@ -57,9 +57,8 @@ JSValue Array_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv,
JSValue thatValue = thisValue;
if (thatValue.isNull())
thatValue = Array_Type->newInstance(cx);
ASSERT(thatValue.isObject());
JSObject *thisObj = thatValue.object;
JSArrayInstance *arrInst = checked_cast<JSArrayInstance *>(thisObj);
ASSERT(thatValue.isInstance());
JSArrayInstance *arrInst = checked_cast<JSArrayInstance *>(thatValue.instance);
if (argc > 0) {
if (argc == 1) {
if (argv[0].isNumber()) {
@ -89,9 +88,11 @@ JSValue Array_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv,
static JSValue Array_toString(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
{
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
JSArrayInstance *arrInst = checked_cast<JSArrayInstance *>(thisObj);
if (thisValue.getType() != Array_Type)
cx->reportError(Exception::typeError, "Array.prototype.toString called on a non Array");
ASSERT(thisValue.isInstance());
JSArrayInstance *arrInst = checked_cast<JSArrayInstance *>(thisValue.instance);
ContextStackReplacement csr(cx);
@ -107,6 +108,7 @@ static JSValue Array_toString(Context *cx, const JSValue& thisValue, JSValue * /
s->append(*result.toString(cx).string);
if (i < (arrInst->mLength - 1))
s->append(widenCString(","));
delete id;
}
return JSValue(s);
}
@ -115,9 +117,11 @@ static JSValue Array_toString(Context *cx, const JSValue& thisValue, JSValue * /
static JSValue Array_toSource(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
{
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
JSArrayInstance *arrInst = checked_cast<JSArrayInstance *>(thisObj);
if (thisValue.getType() != Array_Type)
cx->reportError(Exception::typeError, "Array.prototype.toSource called on a non Array");
ASSERT(thisValue.isInstance());
JSArrayInstance *arrInst = checked_cast<JSArrayInstance *>(thisValue.instance);
ContextStackReplacement csr(cx);
@ -133,6 +137,7 @@ static JSValue Array_toSource(Context *cx, const JSValue& thisValue, JSValue * /
s->append(*result.toString(cx).string);
if (i < (arrInst->mLength - 1))
s->append(widenCString(", "));
delete id;
}
s->append(widenCString("]"));
return JSValue(s);
@ -142,33 +147,40 @@ static JSValue Array_toSource(Context *cx, const JSValue& thisValue, JSValue * /
static JSValue Array_push(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
JSArrayInstance *arrInst = checked_cast<JSArrayInstance *>(thisObj);
ContextStackReplacement csr(cx);
JSObject *thisObj = thisValue.getObjectValue();
thisObj->getProperty(cx, cx->Length_StringAtom, CURRENT_ATTR);
JSValue result = cx->popValue();
uint32 length = (uint32)(result.toUInt32(cx).f64);
for (uint32 i = 0; i < argc; i++) {
const String *id = numberToString(i + arrInst->mLength);
arrInst->defineVariable(cx, *id, (NamespaceList *)(NULL), Property::NoAttribute, Object_Type, argv[i]);
const String *id = numberToString(i + length);
thisObj->defineVariable(cx, *id, (NamespaceList *)(NULL), Property::NoAttribute, Object_Type, argv[i]);
delete id;
}
arrInst->mLength += argc;
return JSValue((float64)arrInst->mLength);
length += argc;
result = JSValue((float64)length);
thisObj->setProperty(cx, cx->Length_StringAtom, CURRENT_ATTR, result);
return result;
}
static JSValue Array_pop(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
{
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
JSArrayInstance *arrInst = checked_cast<JSArrayInstance *>(thisObj);
ContextStackReplacement csr(cx);
if (arrInst->mLength > 0) {
const String *id = numberToString(arrInst->mLength - 1);
arrInst->getProperty(cx, *id, NULL);
JSObject *thisObj = thisValue.getObjectValue();
thisObj->getProperty(cx, cx->Length_StringAtom, CURRENT_ATTR);
JSValue result = cx->popValue();
uint32 length = (uint32)(result.toUInt32(cx).f64);
if (length > 0) {
const String *id = numberToString(length - 1);
thisObj->getProperty(cx, *id, NULL);
JSValue result = cx->popValue();
arrInst->deleteProperty(cx, *id, NULL);
--arrInst->mLength;
thisObj->deleteProperty(cx, *id, NULL);
--length;
thisObj->setProperty(cx, cx->Length_StringAtom, CURRENT_ATTR, JSValue((float64)length));
delete id;
return result;
}
@ -180,7 +192,8 @@ JSValue Array_concat(Context *cx, const JSValue& thisValue, JSValue *argv, uint3
{
JSValue E = thisValue;
JSArrayInstance *A = (JSArrayInstance *)(Array_Type->newInstance(cx));
JSValue result = Array_Type->newInstance(cx);
JSArrayInstance *A = checked_cast<JSArrayInstance *>(result.instance);
uint32 n = 0;
uint32 i = 0;
@ -190,30 +203,34 @@ JSValue Array_concat(Context *cx, const JSValue& thisValue, JSValue *argv, uint3
if (E.getType() != Array_Type) {
const String *id = numberToString(n++);
A->setProperty(cx, *id, CURRENT_ATTR, E);
delete id;
}
else {
ASSERT(E.isObject());
JSArrayInstance *arrInst = checked_cast<JSArrayInstance *>(E.object);
for (uint32 k = 0; k < arrInst->mLength; k++) {
JSObject *arrObj = E.getObjectValue();
arrObj->getProperty(cx, cx->Length_StringAtom, CURRENT_ATTR);
JSValue result = cx->popValue();
uint32 length = (uint32)(result.toUInt32(cx).f64);
for (uint32 k = 0; k < length; k++) {
const String *id = numberToString(k);
arrInst->getProperty(cx, *id, NULL);
JSValue result = cx->popValue();
arrObj->getProperty(cx, *id, NULL);
delete id;
id = numberToString(n++);
JSValue result = cx->popValue();
A->setProperty(cx, *id, CURRENT_ATTR, result);
delete id;
}
}
E = argv[i++];
} while (i <= argc);
return JSValue(A);
return result;
}
static JSValue Array_join(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ContextStackReplacement csr(cx);
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
JSObject *thisObj = thisValue.getObjectValue();
thisObj->getProperty(cx, cx->Length_StringAtom, CURRENT_ATTR);
JSValue result = cx->popValue();
@ -230,19 +247,23 @@ static JSValue Array_join(Context *cx, const JSValue& thisValue, JSValue *argv,
else
separator = argv[0].toString(cx).string;
thisObj->getProperty(cx, *numberToString(0), CURRENT_ATTR);
const String *id = numberToString(0);
thisObj->getProperty(cx, *id, CURRENT_ATTR);
delete id;
result = cx->popValue();
String *S = new String();
for (uint32 k = 0; k < length; k++) {
thisObj->getProperty(cx, *numberToString(k), CURRENT_ATTR);
id = numberToString(k);
thisObj->getProperty(cx, *id, CURRENT_ATTR);
result = cx->popValue();
if (!result.isUndefined() && !result.isNull())
*S += *result.toString(cx).string;
if (k < (length - 1))
*S += *separator;
delete id;
}
return JSValue(S);
@ -252,8 +273,7 @@ static JSValue Array_reverse(Context *cx, const JSValue& thisValue, JSValue * /*
{
ContextStackReplacement csr(cx);
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
JSObject *thisObj = thisValue.getObjectValue();
thisObj->getProperty(cx, cx->Length_StringAtom, CURRENT_ATTR);
JSValue result = cx->popValue();
@ -290,6 +310,8 @@ static JSValue Array_reverse(Context *cx, const JSValue& thisValue, JSValue * /*
thisObj->deleteProperty(cx, *id2, CURRENT_ATTR);
}
}
delete id1;
delete id2;
}
return thisValue;
@ -299,8 +321,7 @@ static JSValue Array_shift(Context *cx, const JSValue& thisValue, JSValue * /*ar
{
ContextStackReplacement csr(cx);
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
JSObject *thisObj = thisValue.getObjectValue();
thisObj->getProperty(cx, cx->Length_StringAtom, CURRENT_ATTR);
JSValue result = cx->popValue();
@ -311,8 +332,10 @@ static JSValue Array_shift(Context *cx, const JSValue& thisValue, JSValue * /*ar
return kUndefinedValue;
}
thisObj->getProperty(cx, *numberToString(0), CURRENT_ATTR);
const String *id = numberToString(0);
thisObj->getProperty(cx, *id, CURRENT_ATTR);
result = cx->popValue();
delete id;
for (uint32 k = 1; k < length; k++) {
const String *id1 = numberToString(k);
@ -325,9 +348,13 @@ static JSValue Array_shift(Context *cx, const JSValue& thisValue, JSValue * /*ar
}
else
thisObj->deleteProperty(cx, *id2, CURRENT_ATTR);
delete id1;
delete id2;
}
thisObj->deleteProperty(cx, *numberToString(length - 1), CURRENT_ATTR);
id = numberToString(length - 1);
thisObj->deleteProperty(cx, *id, CURRENT_ATTR);
delete id;
thisObj->setProperty(cx, cx->Length_StringAtom, CURRENT_ATTR, JSValue((float64)(length - 1)) );
return result;
@ -337,14 +364,14 @@ static JSValue Array_slice(Context *cx, const JSValue& thisValue, JSValue *argv,
{
ContextStackReplacement csr(cx);
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
JSObject *thisObj = thisValue.getObjectValue();
JSArrayInstance *A = (JSArrayInstance *)Array_Type->newInstance(cx);
JSValue result = Array_Type->newInstance(cx);
JSArrayInstance *A = checked_cast<JSArrayInstance *>(result.instance);
thisObj->getProperty(cx, cx->Length_StringAtom, CURRENT_ATTR);
JSValue result = cx->popValue();
uint32 length = (uint32)(result.toUInt32(cx).f64);
JSValue lengthValue = cx->popValue();
uint32 length = (uint32)(lengthValue.toUInt32(cx).f64);
uint32 start, end;
if (argc < 1)
@ -396,6 +423,7 @@ static JSValue Array_slice(Context *cx, const JSValue& thisValue, JSValue *argv,
}
n++;
start++;
delete id1;
}
A->setProperty(cx, cx->Length_StringAtom, CURRENT_ATTR, JSValue((float64)n) );
return JSValue(A);
@ -517,7 +545,6 @@ static int32 sort_compare(JSValue *a, JSValue *b, CompareArgs *arg)
static JSValue Array_sort(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ASSERT(thisValue.isObject());
ContextStackReplacement csr(cx);
CompareArgs ca;
@ -532,7 +559,7 @@ static JSValue Array_sort(Context *cx, const JSValue& thisValue, JSValue *argv,
}
}
JSObject *thisObj = thisValue.object;
JSObject *thisObj = thisValue.getObjectValue();
thisObj->getProperty(cx, cx->Length_StringAtom, CURRENT_ATTR);
JSValue result = cx->popValue();
uint32 length = (uint32)(result.toUInt32(cx).f64);
@ -566,13 +593,13 @@ static JSValue Array_splice(Context *cx, const JSValue& thisValue, JSValue *argv
uint32 k;
ContextStackReplacement csr(cx);
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
JSObject *thisObj = thisValue.getObjectValue();
thisObj->getProperty(cx, cx->Length_StringAtom, CURRENT_ATTR);
JSValue result = cx->popValue();
uint32 length = (uint32)(result.toUInt32(cx).f64);
JSValue lengthValue = cx->popValue();
uint32 length = (uint32)(lengthValue.toUInt32(cx).f64);
JSArrayInstance *A = (JSArrayInstance *)Array_Type->newInstance(cx);
JSValue result = Array_Type->newInstance(cx);
JSArrayInstance *A = checked_cast<JSArrayInstance *>(result.instance);
int32 arg0 = (int32)(argv[0].toInt32(cx).f64);
uint32 start;
@ -608,6 +635,7 @@ static JSValue Array_splice(Context *cx, const JSValue& thisValue, JSValue *argv
thisObj->getProperty(cx, *id1, CURRENT_ATTR);
A->setProperty(cx, *id2, CURRENT_ATTR, cx->popValue());
}
delete id1;
}
A->setProperty(cx, cx->Length_StringAtom, CURRENT_ATTR, JSValue((float64)deleteCount) );
@ -623,6 +651,8 @@ static JSValue Array_splice(Context *cx, const JSValue& thisValue, JSValue *argv
}
else
thisObj->deleteProperty(cx, *id2, CURRENT_ATTR);
delete id1;
delete id2;
}
for (k = length; k > (length - deleteCount + newItemCount); k--) {
const String *id1 = numberToString(k - 1);
@ -641,6 +671,8 @@ static JSValue Array_splice(Context *cx, const JSValue& thisValue, JSValue *argv
}
else
thisObj->deleteProperty(cx, *id2, CURRENT_ATTR);
delete id1;
delete id2;
}
}
}
@ -648,10 +680,11 @@ static JSValue Array_splice(Context *cx, const JSValue& thisValue, JSValue *argv
for (uint32 i = 2; i < argc; i++) {
const String *id1 = numberToString(k++);
thisObj->setProperty(cx, *id1, CURRENT_ATTR, argv[i]);
delete id1;
}
thisObj->setProperty(cx, cx->Length_StringAtom, CURRENT_ATTR, JSValue((float64)(length - deleteCount + newItemCount)) );
return JSValue(A);
return result;
}
return kUndefinedValue;
}
@ -660,8 +693,7 @@ static JSValue Array_unshift(Context *cx, const JSValue& thisValue, JSValue *arg
{
ContextStackReplacement csr(cx);
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
JSObject *thisObj = thisValue.getObjectValue();
thisObj->getProperty(cx, cx->Length_StringAtom, CURRENT_ATTR);
JSValue result = cx->popValue();
uint32 length = (uint32)(result.toUInt32(cx).f64);
@ -677,11 +709,14 @@ static JSValue Array_unshift(Context *cx, const JSValue& thisValue, JSValue *arg
}
else
thisObj->deleteProperty(cx, *id2, CURRENT_ATTR);
delete id1;
delete id2;
}
for (k = 0; k < argc; k++) {
const String *id1 = numberToString(k);
thisObj->setProperty(cx, *id1, CURRENT_ATTR, argv[k]);
delete id1;
}
thisObj->setProperty(cx, cx->Length_StringAtom, CURRENT_ATTR, JSValue((float64)(length + argc)) );
@ -712,10 +747,7 @@ JSValue Array_GetElement(Context *cx, const JSValue& thisValue, JSValue *argv, u
if (argc != 2)
cx->reportError(Exception::referenceError, "[] only supports single dimension");
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
JSArrayInstance *arrInst = checked_cast<JSArrayInstance *>(thisObj);
ASSERT(thisObj->mType == Array_Type);
JSArrayInstance *arrInst = checked_cast<JSArrayInstance *>(thisValue.instance);
JSValue index = argv[1];
const String *name = index.toString(cx).string;
@ -730,10 +762,7 @@ JSValue Array_SetElement(Context *cx, const JSValue& thisValue, JSValue *argv, u
if (argc != 3)
cx->reportError(Exception::referenceError, "[]= only supports single dimension");
ASSERT(thisValue.isObject());
JSObject *thisObj = thisValue.object;
JSArrayInstance *arrInst = checked_cast<JSArrayInstance *>(thisObj);
ASSERT(thisObj->mType == Array_Type);
JSArrayInstance *arrInst = checked_cast<JSArrayInstance *>(thisValue.instance);
JSValue index = argv[2];
const String *name = index.toString(cx).string;
@ -741,9 +770,9 @@ JSValue Array_SetElement(Context *cx, const JSValue& thisValue, JSValue *argv, u
if (index.isNumber()) {
uint32 intIndex;
if (isArrayIndex(cx, index, intIndex)) {
PropertyIterator it = thisObj->findNamespacedProperty(*name, NULL);
if (it == thisObj->mProperties.end())
thisObj->insertNewProperty(*name, NULL, Property::Enumerable, Object_Type, argv[1]);
PropertyIterator it = arrInst->findNamespacedProperty(*name, NULL);
if (it == arrInst->mProperties.end())
arrInst->insertNewProperty(*name, NULL, Property::Enumerable, Object_Type, argv[1]);
else {
Property *prop = PROPERTY(it);
ASSERT(prop->mFlag == ValuePointer);

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

@ -291,11 +291,12 @@ static int32 WeekDay(float64 t)
static float64 *Date_getProlog(Context *cx, const JSValue& thisValue)
{
ASSERT(thisValue.isObject());
if (thisValue.getType() != Date_Type)
cx->reportError(Exception::typeError, "You need a date");
ASSERT(thisValue.isInstance());
JSDateInstance *dateInst = checked_cast<JSDateInstance *>(thisValue.instance);
return (float64 *)(thisValue.object->mPrivate);
return &dateInst->mValue;
}
@ -869,9 +870,8 @@ JSValue Date_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, u
JSValue thatValue = thisValue;
if (thatValue.isNull())
thatValue = Date_Type->newInstance(cx);
ASSERT(thatValue.isObject());
JSObject *thisObj = thatValue.object;
thisObj->mPrivate = new float64;
ASSERT(thatValue.isInstance());
JSDateInstance *thisInst = checked_cast<JSDateInstance *>(thatValue.instance);
/* Date called as constructor */
if (argc == 0) {
@ -883,20 +883,20 @@ JSValue Date_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, u
JSLL_DIV(ms, us, us2ms);
JSLL_L2D(msec_time, ms);
*((float64 *)(thisObj->mPrivate)) = msec_time;
thisInst->mValue = 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);
thisInst->mValue = 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);
thisInst->mValue = TIMECLIP(d);
}
}
else {
@ -911,7 +911,7 @@ JSValue Date_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, u
/* if any arg is NaN, make a NaN date object
and return */
if (!JSDOUBLE_IS_FINITE(double_arg)) {
*((float64 *)(thisObj->mPrivate)) = nan;
thisInst->mValue = nan;
return thatValue;
}
array[loop] = JSValue::float64ToInteger(double_arg);
@ -931,7 +931,7 @@ JSValue Date_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, u
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);
thisInst->mValue = TIMECLIP(msec_time);
}
}
return thatValue;

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

@ -45,7 +45,6 @@
#include "js2runtime.h"
#include "jsstring.h"
#include "regexp.h"
namespace JavaScript {
namespace JS2Runtime {
@ -56,15 +55,13 @@ JSValue String_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv,
JSValue thatValue = thisValue;
if (thatValue.isNull())
thatValue = String_Type->newInstance(cx);
ASSERT(thatValue.isObject());
JSObject *thisObj = thatValue.object;
JSStringInstance *strInst = checked_cast<JSStringInstance *>(thisObj);
ASSERT(thatValue.isInstance());
JSStringInstance *strInst = checked_cast<JSStringInstance *>(thatValue.instance);
if (argc > 0)
thisObj->mPrivate = (void *)(new String(*argv[0].toString(cx).string));
strInst->mValue = new String(*argv[0].toString(cx).string);
else
thisObj->mPrivate = (void *)(&cx->Empty_StringAtom);
strInst->mLength = ((String *)(thisObj->mPrivate))->size();
strInst->mValue = &cx->Empty_StringAtom;
return thatValue;
}
@ -89,85 +86,105 @@ JSValue String_fromCharCode(Context *cx, const JSValue& /*thisValue*/, JSValue *
static JSValue String_toString(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
{
ASSERT(thisValue.isObject());
if (thisValue.getType() != String_Type)
cx->reportError(Exception::typeError, "String.toString called on something other than a string thing");
JSObject *thisObj = thisValue.object;
return JSValue((String *)thisObj->mPrivate);
ASSERT(thisValue.isInstance());
JSStringInstance *strInst = checked_cast<JSStringInstance *>(thisValue.instance);
return JSValue(strInst->mValue);
}
static JSValue String_valueOf(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
{
ASSERT(thisValue.isObject());
if (thisValue.getType() != String_Type)
cx->reportError(Exception::typeError, "String.valueOf called on something other than a string thing");
JSObject *thisObj = thisValue.object;
return JSValue((String *)thisObj->mPrivate);
ASSERT(thisValue.isInstance());
JSStringInstance *strInst = checked_cast<JSStringInstance *>(thisValue.instance);
return JSValue(strInst->mValue);
}
/*
* 15.5.4.12 String.prototype.search (regexp)
*
* If regexp is not an object whose [[Class]] property is "RegExp", it is replaced with the result of the expression new
* RegExp(regexp). Let string denote the result of converting the this value to a string.
* The value string is searched from its beginning for an occurrence of the regular expression pattern regexp. The
* result is a number indicating the offset within the string where the pattern matched, or -1 if there was no match.
* NOTE This method ignores the lastIndex and global properties of regexp. The lastIndex property of regexp is left
* unchanged.
*/
static JSValue String_search(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ContextStackReplacement csr(cx);
ASSERT(thisValue.isObject() || thisValue.isFunction() || thisValue.isType());
JSValue S = thisValue.toString(cx);
JSValue regexp = argv[0];
if ((argc == 0) || !regexp.isObject() || (regexp.object->mType != RegExp_Type)) {
if ((argc == 0) || (regexp.getType() != RegExp_Type)) {
regexp = kNullValue;
regexp = RegExp_Constructor(cx, regexp, argv, 1);
}
REParseState *parseResult = (REParseState *)(regexp.object->mPrivate);
REState *pState = (checked_cast<JSRegExpInstance *>(regexp.instance))->mRegExp;
/* save & restore lastIndex as it's not to be modified */
uint32 lastIndex = parseResult->lastIndex;
parseResult->lastIndex = 0;
REState *regexp_result = REExecute(parseResult, S.string->begin(), S.string->length());
parseResult->lastIndex = lastIndex;
if (regexp_result)
return JSValue((float64)(regexp_result->startIndex));
REMatchState *match = REExecute(pState, S.string->begin(), 0, S.string->length(), false);
if (match)
return JSValue((float64)(match->startIndex));
else
return JSValue(-1.0);
}
/*
* 15.5.4.10 String.prototype.match (regexp)
*
* If regexp is not an object whose [[Class]] property is "RegExp", it is replaced with the result of the expression new
* RegExp(regexp). Let string denote the result of converting the this value to a string. Then do one of the following:
* - If regexp.global is false: Return the result obtained by invoking RegExp.prototype.exec (see section
* 15.10.6.2) on regexp with string as parameter.
* - If regexp.global is true: Set the regexp.lastIndex property to 0 and invoke RegExp.prototype.exec
* repeatedly until there is no match. If there is a match with an empty string (in other words, if the value of
* regexp.lastIndex is left unchanged), increment regexp.lastIndex by 1. Let n be the number of matches. The
* value returned is an array with the length property set to n and properties 0 through n-1 corresponding to the
* first elements of the results of all matching invocations of RegExp.prototype.exec.
*/
static JSValue String_match(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ContextStackReplacement csr(cx);
ASSERT(thisValue.isObject() || thisValue.isFunction() || thisValue.isType());
JSValue S = thisValue.toString(cx);
JSValue regexp = argv[0];
if ((argc == 0) || !regexp.isObject() || (regexp.object->mType != RegExp_Type)) {
if ((argc == 0) || (regexp.getType() != RegExp_Type)) {
regexp = kNullValue;
regexp = RegExp_Constructor(cx, regexp, argv, 1);
}
REParseState *parseResult = (REParseState *)(regexp.object->mPrivate);
if ((parseResult->flags & GLOBAL) == 0) {
REState *pState = (checked_cast<JSRegExpInstance *>(regexp.instance))->mRegExp;
if ((pState->flags & RE_GLOBAL) == 0) {
return RegExp_exec(cx, regexp, &S, 1);
}
else {
JSArrayInstance *A = (JSArrayInstance *)Array_Type->newInstance(cx);
parseResult->lastIndex = 0;
JSValue result = Array_Type->newInstance(cx);
JSArrayInstance *A = checked_cast<JSArrayInstance *>(result.instance);
int32 index = 0;
int32 lastIndex = 0;
while (true) {
REState *regexp_result = REExecute(parseResult, S.string->begin(), S.string->length());
if (regexp_result == NULL)
REMatchState *match = REExecute(pState, S.string->begin(), lastIndex, S.string->length(), false);
if (match == NULL)
break;
if (parseResult->lastIndex == index)
parseResult->lastIndex++;
String *matchStr = new String(S.string->substr(regexp_result->startIndex, regexp_result->endIndex - regexp_result->startIndex));
if (lastIndex == match->endIndex)
lastIndex++;
else
lastIndex = match->endIndex;
String *matchStr = new String(S.string->substr(match->startIndex, match->endIndex - match->startIndex));
A->setProperty(cx, *numberToString(index++), NULL, JSValue(matchStr));
}
regexp.object->setProperty(cx, cx->LastIndex_StringAtom, NULL, JSValue((float64)(parseResult->lastIndex)));
return JSValue(A);
regexp.instance->setProperty(cx, cx->LastIndex_StringAtom, NULL, JSValue((float64)lastIndex));
return result;
}
}
static const String interpretDollar(Context *cx, const String *replaceStr, uint32 dollarPos, const String *searchStr, REState *regexp_result, uint32 &skip)
static const String interpretDollar(Context *cx, const String *replaceStr, uint32 dollarPos, const String *searchStr, REMatchState *match, uint32 &skip)
{
skip = 2;
const char16 *dollarValue = replaceStr->begin() + dollarPos + 1;
@ -175,11 +192,11 @@ static const String interpretDollar(Context *cx, const String *replaceStr, uint3
case '$':
return cx->Dollar_StringAtom;
case '&':
return searchStr->substr(regexp_result->startIndex, regexp_result->endIndex - regexp_result->startIndex);
return searchStr->substr(match->startIndex, match->endIndex - match->startIndex);
case '`':
return searchStr->substr(0, regexp_result->startIndex);
return searchStr->substr(0, match->startIndex);
case '\'':
return searchStr->substr(regexp_result->endIndex, searchStr->length() - regexp_result->endIndex);
return searchStr->substr(match->endIndex, searchStr->length() - match->endIndex);
case '0':
case '1':
case '2':
@ -192,16 +209,16 @@ static const String interpretDollar(Context *cx, const String *replaceStr, uint3
case '9':
{
int32 num = (uint32)(*dollarValue - '0');
if (num <= regexp_result->n) {
if (num <= match->parenCount) {
if ((dollarPos < (replaceStr->length() - 2))
&& (dollarValue[1] >= '0') && (dollarValue[1] <= '9')) {
int32 tmp = (num * 10) + (dollarValue[1] - '0');
if (tmp <= regexp_result->n) {
if (tmp <= match->parenCount) {
num = tmp;
skip = 3;
}
}
return searchStr->substr((uint32)(regexp_result->parens[num - 1].index), (uint32)(regexp_result->parens[num - 1].length));
return searchStr->substr((uint32)(match->parens[num - 1].index), (uint32)(match->parens[num - 1].length));
}
}
// fall thru
@ -211,9 +228,37 @@ static const String interpretDollar(Context *cx, const String *replaceStr, uint3
}
}
/*
* 15.5.4.11 String.prototype.replace (searchValue, replaceValue)
*
* Let string denote the result of converting the this value to a string.
*
* If searchValue is a regular expression (an object whose [[Class]] property is "RegExp"), do the following: If
* searchValue.global is false, then search string for the first match of the regular expression searchValue. If
* searchValue.global is true, then search string for all matches of the regular expression searchValue. Do the search
* in the same manner as in String.prototype.match, including the update of searchValue.lastIndex. Let m
* be the number of left capturing parentheses in searchValue (NCapturingParens as specified in section 15.10.2.1).
*
* If searchValue is not a regular expression, let searchString be ToString(searchValue) and search string for the first
* occurrence of searchString. Let m be 0.
*
* If replaceValue is a function, then for each matched substring, call the function with the following m + 3 arguments.
* Argument 1 is the substring that matched. If searchValue is a regular expression, the next m arguments are all of
* the captures in the MatchResult (see section 15.10.2.1). Argument m + 2 is the offset within string where the match
* occurred, and argument m + 3 is string. The result is a string value derived from the original input by replacing each
* matched substring with the corresponding return value of the function call, converted to a string if need be.
*
* Otherwise, let newstring denote the result of converting replaceValue to a string. The result is a string value derived
* from the original input string by replacing each matched substring with a string derived from newstring by replacing
* characters in newstring by replacement text as specified in the following table. These $ replacements are done left-to-
* right, and, once such a replacement is performed, the new replacement text is not subject to further
* replacements. For example, "$1,$2".replace(/(\$(\d))/g, "$$1-$1$2") returns "$1-$11,$1-$22". A
* $ in newstring that does not match any of the forms below is left as is.
*/
static JSValue String_replace(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ASSERT(thisValue.isObject() || thisValue.isFunction() || thisValue.isType());
JSValue S = thisValue.toString(cx);
JSValue searchValue;
@ -223,54 +268,58 @@ static JSValue String_replace(Context *cx, const JSValue& thisValue, JSValue *ar
if (argc > 1) replaceValue = argv[1];
const String *replaceStr = replaceValue.toString(cx).string;
if (searchValue.isObject() && (searchValue.object->mType == RegExp_Type)) {
REParseState *parseResult = (REParseState *)(searchValue.object->mPrivate);
REState *regexp_result;
uint32 m = parseResult->parenCount;
if (searchValue.getType() == RegExp_Type) {
REState *pState = (checked_cast<JSRegExpInstance *>(searchValue.instance))->mRegExp;
REMatchState *match;
uint32 m = pState->parenCount;
String newString;
uint32 index = 0;
int32 lastIndex = 0;
while (true) {
if (parseResult->flags & GLOBAL)
parseResult->lastIndex = (int32)index;
regexp_result = REExecute(parseResult, S.string->begin(), S.string->length());
if (regexp_result) {
match = REExecute(pState, S.string->begin(), lastIndex, S.string->length(), false);
if (match) {
String insertString;
uint32 start = 0;
while (true) {
// look for '$' in the replacement string and interpret it as necessary
uint32 dollarPos = replaceStr->find('$', start);
if ((dollarPos != String::npos) && (dollarPos < (replaceStr->length() - 1))) {
uint32 skip;
insertString += replaceStr->substr(start, dollarPos - start);
insertString += interpretDollar(cx, replaceStr, dollarPos, S.string, regexp_result, skip);
insertString += interpretDollar(cx, replaceStr, dollarPos, S.string, match, skip);
start = dollarPos + skip;
}
else {
// otherwise, absorb the entire replacement string
insertString += replaceStr->substr(start, replaceStr->length() - start);
break;
}
}
newString += S.string->substr(index, regexp_result->startIndex - index);
// grab everything preceding the match
newString += S.string->substr(lastIndex, match->startIndex - lastIndex);
// and then add the replacement string
newString += insertString;
}
else
break;
index = regexp_result->endIndex;
if ((parseResult->flags & GLOBAL) == 0)
lastIndex = match->endIndex; // use lastIndex to grab remainder after break
if ((pState->flags & RE_GLOBAL) == 0)
break;
}
newString += S.string->substr(index, S.string->length() - index);
newString += S.string->substr(lastIndex, S.string->length() - lastIndex);
if ((pState->flags & RE_GLOBAL) == 0)
searchValue.instance->setProperty(cx, cx->LastIndex_StringAtom, NULL, JSValue((float64)lastIndex));
return JSValue(new String(newString));
}
else {
const String *searchStr = searchValue.toString(cx).string;
REState regexp_result;
REMatchState match;
uint32 pos = S.string->find(*searchStr, 0);
if (pos == String::npos)
return JSValue(S.string);
regexp_result.startIndex = (int32)pos;
regexp_result.endIndex = regexp_result.startIndex + searchStr->length();
regexp_result.n = 0;
match.startIndex = (int32)pos;
match.endIndex = match.startIndex + searchStr->length();
match.parenCount = 0;
String insertString;
String newString;
uint32 start = 0;
@ -279,7 +328,7 @@ static JSValue String_replace(Context *cx, const JSValue& thisValue, JSValue *ar
if ((dollarPos != String::npos) && (dollarPos < (replaceStr->length() - 1))) {
uint32 skip;
insertString += replaceStr->substr(start, dollarPos - start);
insertString += interpretDollar(cx, replaceStr, dollarPos, S.string, &regexp_result, skip);
insertString += interpretDollar(cx, replaceStr, dollarPos, S.string, &match, skip);
start = dollarPos + skip;
}
else {
@ -287,9 +336,9 @@ static JSValue String_replace(Context *cx, const JSValue& thisValue, JSValue *ar
break;
}
}
newString += S.string->substr(0, regexp_result.startIndex);
newString += S.string->substr(0, match.startIndex);
newString += insertString;
uint32 index = regexp_result.endIndex;
uint32 index = match.endIndex;
newString += S.string->substr(index, S.string->length() - index);
return JSValue(new String(newString));
}
@ -320,23 +369,23 @@ static void strSplitMatch(const String *S, uint32 q, const String *R, MatchResul
result.failure = false;
}
static void regexpSplitMatch(const String *S, uint32 q, REParseState *RE, MatchResult &result)
static void regexpSplitMatch(const String *S, uint32 q, REState *RE, MatchResult &result)
{
result.failure = true;
result.captures = NULL;
REState *regexp_result = REMatch(RE, S->begin() + q, S->length() - q);
REMatchState *match = REMatch(RE, S->begin() + q, S->length() - q);
if (regexp_result) {
result.endIndex = regexp_result->startIndex + q;
if (match) {
result.endIndex = match->startIndex + q;
result.failure = false;
result.capturesCount = regexp_result->n;
if (regexp_result->n) {
result.captures = new JSValue[regexp_result->n];
for (int32 i = 0; i < regexp_result->n; i++) {
if (regexp_result->parens[i].index != -1) {
String *parenStr = new String(S->substr((uint32)(regexp_result->parens[i].index + q),
(uint32)(regexp_result->parens[i].length)));
result.capturesCount = match->parenCount;
if (match->parenCount) {
result.captures = new JSValue[match->parenCount];
for (int32 i = 0; i < match->parenCount; i++) {
if (match->parens[i].index != -1) {
String *parenStr = new String(S->substr((uint32)(match->parens[i].index + q),
(uint32)(match->parens[i].length)));
result.captures[i] = JSValue(parenStr);
}
else
@ -351,10 +400,10 @@ static JSValue String_split(Context *cx, const JSValue& thisValue, JSValue *argv
{
ContextStackReplacement csr(cx);
ASSERT(thisValue.isObject() || thisValue.isFunction() || thisValue.isType());
JSValue S = thisValue.toString(cx);
JSArrayInstance *A = (JSArrayInstance *)Array_Type->newInstance(cx);
JSValue result = Array_Type->newInstance(cx);
JSArrayInstance *A = checked_cast<JSArrayInstance *>(result.instance);
uint32 lim;
JSValue separatorV = (argc > 0) ? argv[0] : kUndefinedValue;
JSValue limitV = (argc > 1) ? argv[1] : kUndefinedValue;
@ -367,15 +416,15 @@ static JSValue String_split(Context *cx, const JSValue& thisValue, JSValue *argv
uint32 s = S.string->size();
uint32 p = 0;
REParseState *RE = NULL;
REState *RE = NULL;
const String *R = NULL;
if (separatorV.isObject() && (separatorV.object->mType == RegExp_Type))
RE = (REParseState *)(separatorV.object->mPrivate);
if (separatorV.getType() == RegExp_Type)
RE = (checked_cast<JSRegExpInstance *>(separatorV.instance))->mRegExp;
else
R = separatorV.toString(cx).string;
if (lim == 0)
return JSValue(A);
return result;
/* XXX standard requires this, but Monkey doesn't do it and the tests break
@ -391,9 +440,9 @@ static JSValue String_split(Context *cx, const JSValue& thisValue, JSValue *argv
else
strSplitMatch(S.string, 0, R, z);
if (!z.failure)
return JSValue(A);
return result;
A->setProperty(cx, widenCString("0"), NULL, S);
return JSValue(A);
return result;
}
while (true) {
@ -403,7 +452,7 @@ step11:
String *T = new String(*S.string, p, (s - p));
JSValue v(T);
A->setProperty(cx, *numberToString(A->mLength), NULL, v);
return JSValue(A);
return result;
}
MatchResult z;
if (RE)
@ -423,20 +472,19 @@ step11:
JSValue v(T);
A->setProperty(cx, *numberToString(A->mLength), NULL, v);
if (A->mLength == lim)
return JSValue(A);
return result;
p = e;
for (uint32 i = 0; i < z.capturesCount; i++) {
A->setProperty(cx, *numberToString(A->mLength), NULL, JSValue(z.captures[i]));
if (A->mLength == lim)
return JSValue(A);
return result;
}
}
}
static JSValue String_charAt(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ASSERT(thisValue.isObject() || thisValue.isFunction() || thisValue.isType());
const String *str = thisValue.toString(cx).string;
uint32 pos = 0;
@ -452,7 +500,6 @@ static JSValue String_charAt(Context *cx, const JSValue& thisValue, JSValue *arg
static JSValue String_charCodeAt(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ASSERT(thisValue.isObject() || thisValue.isFunction() || thisValue.isType());
const String *str = thisValue.toString(cx).string;
uint32 pos = 0;
@ -467,7 +514,6 @@ static JSValue String_charCodeAt(Context *cx, const JSValue& thisValue, JSValue
static JSValue String_concat(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ASSERT(thisValue.isObject() || thisValue.isFunction() || thisValue.isType());
const String *str = thisValue.toString(cx).string;
String *result = new String(*str);
@ -480,7 +526,6 @@ static JSValue String_concat(Context *cx, const JSValue& thisValue, JSValue *arg
static JSValue String_indexOf(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ASSERT(thisValue.isObject() || thisValue.isFunction() || thisValue.isType());
if (argc == 0)
return JSValue(-1.0);
@ -508,7 +553,6 @@ static JSValue String_indexOf(Context *cx, const JSValue& thisValue, JSValue *ar
static JSValue String_lastIndexOf(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ASSERT(thisValue.isObject() || thisValue.isFunction() || thisValue.isType());
if (argc == 0)
return JSValue(-1.0);
@ -543,7 +587,6 @@ static JSValue String_localeCompare(Context * /*cx*/, const JSValue& /*thisValue
static JSValue String_toLowerCase(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
{
ASSERT(thisValue.isObject() || thisValue.isFunction() || thisValue.isType());
JSValue S = thisValue.toString(cx);
String *result = new String(*S.string);
@ -555,7 +598,6 @@ static JSValue String_toLowerCase(Context *cx, const JSValue& thisValue, JSValue
static JSValue String_toUpperCase(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/)
{
ASSERT(thisValue.isObject() || thisValue.isFunction() || thisValue.isType());
JSValue S = thisValue.toString(cx);
String *result = new String(*S.string);
@ -565,9 +607,29 @@ static JSValue String_toUpperCase(Context *cx, const JSValue& thisValue, JSValue
return JSValue(result);
}
/*
* 15.5.4.13 String.prototype.slice (start, end)
*
* The slice method takes two arguments, start and end, and returns a substring of the result of converting this
* object to a string, starting from character position start and running to, but not including, character position end (or
* through the end of the string if end is undefined). If start is negative, it is treated as (sourceLength+start) where
* sourceLength is the length of the string. If end is negative, it is treated as (sourceLength+end) where sourceLength
* is the length of the string. The result is a string value, not a String object.
*
* The following steps are taken:
* 1. Call ToString, giving it the this value as its argument.
* 2. Compute the number of characters in Result(1).
* 3. Call ToInteger(start).
* 4. If end is undefined, use Result(2); else use ToInteger(end).
* 5. If Result(3) is negative, use max(Result(2)+Result(3),0); else use min(Result(3),Result(2)).
* 6. If Result(4) is negative, use max(Result(2)+Result(4),0); else use min(Result(4),Result(2)).
* 7. Compute max(Result(6)Result(5),0).
* 8. Return a string containing Result(7) consecutive characters from Result(1) beginning with the character at
* position Result(5).
*/
static JSValue String_slice(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ASSERT(thisValue.isObject() || thisValue.isFunction() || thisValue.isType());
const String *sourceString = thisValue.toString(cx).string;
uint32 sourceLength = sourceString->size();
@ -616,9 +678,30 @@ static JSValue String_slice(Context *cx, const JSValue& thisValue, JSValue *argv
return JSValue(new String(sourceString->substr(start, end - start)));
}
/*
* 15.5.4.15 String.prototype.substring (start, end)
* The substring method takes two arguments, start and end, and returns a substring of the result of converting this
* object to a string, starting from character position start and running to, but not including, character position end of
* the string (or through the end of the string is end is undefined). The result is a string value, not a String object.
* If either argument is NaN or negative, it is replaced with zero; if either argument is larger than the length of the
* string, it is replaced with the length of the string.
* If start is larger than end, they are swapped.
*
* The following steps are taken:
* 1. Call ToString, giving it the this value as its argument.
* 2. Compute the number of characters in Result(1).
* 3. Call ToInteger(start).
* 4. If end is undefined, use Result(2); else use ToInteger(end).
* 5. Compute min(max(Result(3), 0), Result(2)).
* 6. Compute min(max(Result(4), 0), Result(2)).
* 7. Compute min(Result(5), Result(6)).
* 8. Compute max(Result(5), Result(6)).
* 9. Return a string whose length is the difference between Result(8) and Result(7), containing characters from
* Result(1), namely the characters with indices Result(7) through Result(8)-1, in ascending order.
*/
static JSValue String_substring(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ASSERT(thisValue.isObject() || thisValue.isFunction() || thisValue.isType());
const String *sourceString = thisValue.toString(cx).string;
uint32 sourceLength = sourceString->size();

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -45,96 +45,108 @@ typedef unsigned int REuint32;
typedef int REint32;
typedef unsigned char REuint8;
#ifdef STANDALONE
typedef unsigned char REbool;
enum { false, true };
#else
typedef bool REbool;
#endif
typedef enum RE_FLAGS {
MULTILINE = 0x1,
IGNORECASE = 0x2,
GLOBAL = 0x4
} RE_FLAGS;
typedef enum RE_Flags {
RE_IGNORECASE = 0x1,
RE_GLOBAL = 0x2,
RE_MULTILINE = 0x4
} RE_Flags;
typedef enum REError {
NO_ERROR,
TRAILING_SLASH, /* an backslash just before the end of the RE */
UNCLOSED_PAREN, /* mis-matched parens */
UNCLOSED_BRACKET, /* mis-matched parens */
UNCLOSED_CLASS, /* '[' missing ']' */
BACKREF_IN_CLASS, /* used '\<digit>' in '[..]' */
BAD_FLAG, /* unrecognized flag (not i, g or m) */
WRONG_RANGE, /* range lo > range hi */
OUT_OF_MEMORY
} REError;
typedef enum RE_Version {
RE_VERSION_1, /* octal literal support */
RE_VERSION_2
} RE_Version;
typedef enum RE_Error {
RE_NO_ERROR,
RE_TRAILING_SLASH, /* a backslash just before the end of the RE */
RE_UNCLOSED_PAREN, /* mis-matched parens */
RE_UNCLOSED_BRACKET, /* mis-matched parens */
RE_UNCLOSED_CLASS, /* '[' missing ']' */
RE_BACKREF_IN_CLASS, /* used '\<digit>' in '[..]' */
RE_BAD_FLAG, /* unrecognized flag (not i, g or m) */
RE_WRONG_RANGE, /* range lo > range hi */
RE_OUT_OF_MEMORY
} RE_Error;
typedef struct RENode RENode;
typedef struct CharSet {
typedef struct RECharSet {
REuint8 *bits;
REuint32 length;
REbool sense;
} CharSet;
unsigned char sense;
} RECharSet;
typedef struct REParseState {
typedef struct REState {
REchar *srcStart; /* copy of source text */
REchar *src; /* current parse position */
REchar *srcEnd; /* end of source text */
RENode *result; /* head of result tree */
REuint32 parenCount; /* # capturing parens */
REuint32 flags; /* flags from regexp */
REint32 lastIndex; /* position from last match (for 'g' flag) */
REbool oldSyntax; /* backward compatibility for octal chars */
REError error; /* parse-time error */
REuint32 flags; /* union of flags from regexp */
RE_Version version;
RE_Error error; /* parse-time or runtime error */
REuint32 classCount; /* number of contained []'s */
CharSet *classList; /* data for []'s */
RECharSet *classList; /* data for []'s */
RENode *result; /* head of result tree */
REint32 codeLength; /* length of bytecode */
REuint8 *pc; /* start of bytecode */
} REParseState;
} REState;
typedef struct RECapture {
REint32 index; /* start of contents of this capture, -1 for empty */
REint32 length; /* length of capture */
} RECapture;
typedef struct REState {
REint32 startIndex;
REint32 endIndex;
REint32 n; /* set to (n - 1), i.e. for /((a)b)/, this field is 1 */
typedef struct REMatchState {
REint32 startIndex; /* beginning of succesful match */
REint32 endIndex; /* character beyond end of succesful match */
REint32 parenCount; /* set to (n - 1), i.e. for /((a)b)/, this field is 1 */
RECapture parens[1]; /* first of 'n' captures, allocated at end of this struct */
} REState;
} REMatchState;
/*
* Compiles the RegExp source into a tree of RENodes in the returned
* parse state result field. Errors are flagged via the error reporter
* function and signalled via a NULL return.
* The RegExp source does not have any delimiters and the flag string is
* to be supplied separately (can be NULL, with a 0 length)
* Compiles the flags source text into a union of flag values. Returns RE_NO_ERROR
* or RE_BAD_FLAG.
*
*/
REParseState *REParse(const REchar *source, REint32 sourceLength, const REchar *flags, REint32 flagsLength, REbool oldSyntax);
RE_Error parseFlags(const REchar *flagsSource, REint32 flagsLength, REuint32 *flags);
/*
* The [[Match]] implementation
*
* Compiles the RegExp source into a stream of REByteCodes and fills in the REState struct.
* Errors are recorded in the state 'error' field and signalled by a NULL return.
* The RegExp source does not have any delimiters.
*/
REState *REMatch(REParseState *parseState, const REchar *text, REint32 length);
REState *REParse(const REchar *source, REint32 sourceLength, REuint32 flags, RE_Version version);
/*
* Execute the RegExp against the supplied text, filling in the REState.
*
* Execute the RegExp against the supplied text.
* The return value is NULL for no match, otherwise an REMatchState struct.
*
*/
REState *REExecute(REParseState *parseState, const REchar *text, REint32 length);
REMatchState *REExecute(REState *pState, const REchar *text, REint32 offset, REint32 length, int globalMulitline);
/*
* The [[Match]] implementation, applies the regexp at the start of the text
* only (i.e. it does not search repeatedly through the text for a match).
* NULL return for no match.
*
*/
REMatchState *REMatch(REState *pState, const REchar *text, REint32 length);
/*
* Throw away the RegExp and all data associated with it.
*/
void freeRegExp(REParseState *parseState);
void REfreeRegExp(REState *pState);
/*
* Needs to be provided by the host, following these specs:
@ -151,3 +163,11 @@ void freeRegExp(REParseState *parseState);
* 6. Return cu.
*/
extern REchar canonicalize(REchar ch);
/*
* The host should also provide a definition of whitespace to match the following:
*
*/
#ifndef RE_ISSPACE
#define RE_ISSPACE(c) ( (c == ' ') || (c == '\t') || (c == '\n') || (c == '\r') || (c == '\v') || (c == '\f') )
#endif

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

@ -98,6 +98,10 @@ SOURCE=..\bytecodegen.cpp
# End Source File
# Begin Source File
SOURCE=..\collector.cpp
# End Source File
# Begin Source File
SOURCE=..\exception.cpp
!IF "$(CFG)" == "DikDik - Win32 Release"