зеркало из https://github.com/mozilla/pjs.git
Added boolean class, fixing bugs.
This commit is contained in:
Родитель
26e1214c77
Коммит
c668cc5500
|
@ -0,0 +1,122 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the JavaScript 2 Prototype.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License (the "GPL"), in which case the
|
||||
* provisions of the GPL are applicable instead of those above.
|
||||
* If you wish to allow use of your version of this file only
|
||||
* under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this
|
||||
* file under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "msvc_pragma.h"
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <stack>
|
||||
|
||||
#include "world.h"
|
||||
#include "utilities.h"
|
||||
#include "js2value.h"
|
||||
#include "numerics.h"
|
||||
#include "reader.h"
|
||||
#include "parser.h"
|
||||
#include "regexp.h"
|
||||
#include "js2engine.h"
|
||||
#include "bytecodecontainer.h"
|
||||
#include "js2metadata.h"
|
||||
|
||||
namespace JavaScript {
|
||||
namespace MetaData {
|
||||
|
||||
|
||||
static js2val Boolean_Constructor(JS2Metadata *meta, const js2val thisValue, js2val argv[], uint32 argc)
|
||||
{
|
||||
js2val thatValue = OBJECT_TO_JS2VAL(new BooleanInstance(meta->booleanClass));
|
||||
BooleanInstance *boolInst = checked_cast<BooleanInstance *>(JS2VAL_TO_OBJECT(thatValue));
|
||||
|
||||
if (argc > 0)
|
||||
boolInst->mValue = meta->toBoolean(argv[0]);
|
||||
else
|
||||
boolInst->mValue = false;
|
||||
return thatValue;
|
||||
}
|
||||
|
||||
static js2val Boolean_toString(JS2Metadata *meta, const js2val thisValue, js2val * /*argv*/, uint32 /*argc*/)
|
||||
{
|
||||
if (meta->objectType(thisValue) != meta->booleanClass)
|
||||
meta->reportError(Exception::typeError, "Boolean.toString called on something other than a boolean thing", meta->engine->errorPos());
|
||||
BooleanInstance *boolInst = checked_cast<BooleanInstance *>(JS2VAL_TO_OBJECT(thisValue));
|
||||
return (boolInst->mValue) ? meta->engine->allocString(meta->engine->true_StringAtom) : meta->engine->allocString(meta->engine->false_StringAtom);
|
||||
}
|
||||
|
||||
void initBooleanObject(JS2Metadata *meta)
|
||||
{
|
||||
meta->booleanClass->construct = Boolean_Constructor;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
uint16 length;
|
||||
NativeCode *code;
|
||||
} PrototypeFunction;
|
||||
|
||||
PrototypeFunction prototypeFunctions[] =
|
||||
{
|
||||
{ "toString", 0, Boolean_toString },
|
||||
// { "valueOf", 0, Boolean_valueOf },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
||||
NamespaceList publicNamespaceList;
|
||||
publicNamespaceList.push_back(meta->publicNamespace);
|
||||
|
||||
PrototypeFunction *pf = &prototypeFunctions[0];
|
||||
while (pf->name) {
|
||||
CallableInstance *fInst = new CallableInstance(meta->functionClass);
|
||||
fInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true), pf->code);
|
||||
/*
|
||||
XXX not prototype object function properties, like ECMA3, but members of the Date class
|
||||
meta->writeDynamicProperty(meta->dateClass->prototype, new Multiname(meta->world.identifiers[pf->name], meta->publicNamespace), true, OBJECT_TO_JS2VAL(fInst), RunPhase);
|
||||
*/
|
||||
/*
|
||||
XXX not static members, since those can't be accessed from the instance
|
||||
Variable *v = new Variable(meta->functionClass, OBJECT_TO_JS2VAL(fInst), true);
|
||||
meta->defineStaticMember(&meta->env, &meta->world.identifiers[pf->name], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
|
||||
*/
|
||||
InstanceMember *m = new InstanceMethod(fInst);
|
||||
meta->defineInstanceMember(meta->booleanClass, &meta->cxt, &meta->world.identifiers[pf->name], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, m, 0);
|
||||
pf++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -110,6 +110,11 @@ namespace MetaData {
|
|||
}
|
||||
catch (Exception &jsx) {
|
||||
if (mTryStack.size() > 0) {
|
||||
// The handler for this exception is on the top of the try stack.
|
||||
// It specifies the activation that was active when the try block
|
||||
// was entered. We unwind the activation stack, looking for the
|
||||
// one that matches the handler's. The bytecode container, pc and
|
||||
// sp are all reset appropriately, and execution continues.
|
||||
HandlerData *hndlr = (HandlerData *)mTryStack.top();
|
||||
ActivationFrame *curAct = (activationStackEmpty()) ? NULL : (activationStackTop - 1);
|
||||
|
||||
|
@ -122,6 +127,10 @@ namespace MetaData {
|
|||
if (prev->pc == NULL) {
|
||||
// Yikes! the exception is getting thrown across a re-invocation
|
||||
// of the interpreter loop.
|
||||
// (pc == NULL) is the flag on an activation to indicate that the
|
||||
// interpreter loop was re-invoked (probably a 'load' or 'eval' is
|
||||
// in process). In this case we simply re-throw the exception and let
|
||||
// the prior invocation deal with it.
|
||||
throw jsx;
|
||||
}
|
||||
curAct = --activationStackTop;
|
||||
|
|
|
@ -68,6 +68,7 @@ namespace MetaData {
|
|||
Arena a;
|
||||
Pragma::Flags flags = Pragma::es4;
|
||||
Parser p(world, a, flags, str, fileName);
|
||||
CompilationData *oldData = NULL;
|
||||
try {
|
||||
StmtNode *parsedStatements = p.parseProgram();
|
||||
ASSERT(p.lexer.peek(true).hasKind(Token::end));
|
||||
|
@ -84,16 +85,18 @@ namespace MetaData {
|
|||
stdOut << '\n';
|
||||
}
|
||||
if (parsedStatements) {
|
||||
CompilationData *oldData = startCompilationUnit(NULL, str, fileName);
|
||||
oldData = startCompilationUnit(NULL, str, fileName);
|
||||
ValidateStmtList(parsedStatements);
|
||||
result = ExecuteStmtList(RunPhase, parsedStatements);
|
||||
restoreCompilationUnit(oldData);
|
||||
}
|
||||
}
|
||||
catch (Exception &x) {
|
||||
// ASSERT(false);
|
||||
if (oldData)
|
||||
restoreCompilationUnit(oldData);
|
||||
throw x;
|
||||
}
|
||||
if (oldData)
|
||||
restoreCompilationUnit(oldData);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -2973,6 +2976,14 @@ doUnary:
|
|||
return BOOLEAN_TO_JS2VAL(JSDOUBLE_IS_NaN(d));
|
||||
}
|
||||
|
||||
static js2val GlobalObject_eval(JS2Metadata *meta, const js2val /* thisValue */, js2val argv[], uint32 argc)
|
||||
{
|
||||
if (!JS2VAL_IS_STRING(argv[0]))
|
||||
return argv[0];
|
||||
return meta->readEvalString(*meta->toString(argv[0]), widenCString("Eval Source"));
|
||||
}
|
||||
|
||||
// XXX need length value
|
||||
void JS2Metadata::addGlobalObjectFunction(char *name, NativeCode *code)
|
||||
{
|
||||
CallableInstance *fInst = new CallableInstance(functionClass);
|
||||
|
@ -3015,7 +3026,7 @@ doUnary:
|
|||
|
||||
|
||||
// A 'forbidden' member, used to mark hidden bindings
|
||||
forbiddenMember = new StaticMember(Member::Forbidden);
|
||||
forbiddenMember = new StaticMember(Member::Forbidden, true);
|
||||
|
||||
// needed for class instance variables etc...
|
||||
NamespaceList publicNamespaceList;
|
||||
|
@ -3041,6 +3052,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
|
|||
writeDynamicProperty(glob, new Multiname(&world.identifiers["Infinity"], publicNamespace), true, engine->posInfValue, RunPhase);
|
||||
// Function properties of the global object
|
||||
addGlobalObjectFunction("isNaN", GlobalObject_isNaN);
|
||||
addGlobalObjectFunction("eval", GlobalObject_eval);
|
||||
|
||||
|
||||
/*** ECMA 3 Object Class ***/
|
||||
|
@ -3075,6 +3087,11 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
|
|||
defineStaticMember(env, &world.identifiers["Number"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
|
||||
initNumberObject(this);
|
||||
|
||||
/*** ECMA 3 Boolean Class ***/
|
||||
v = new Variable(classClass, OBJECT_TO_JS2VAL(booleanClass), true);
|
||||
defineStaticMember(env, &world.identifiers["Boolean"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
|
||||
initBooleanObject(this);
|
||||
|
||||
/*** ECMA 3 Math Class ***/
|
||||
MAKEBUILTINCLASS(mathClass, objectClass, true, true, true, &world.identifiers["Math"]);
|
||||
v = new Variable(classClass, OBJECT_TO_JS2VAL(mathClass), true);
|
||||
|
@ -4198,6 +4215,7 @@ deleteClassProperty:
|
|||
bConList.pop_back();
|
||||
|
||||
bCon = oldData->bCon;
|
||||
engine->bCon = bCon;
|
||||
|
||||
delete oldData;
|
||||
}
|
||||
|
@ -4345,7 +4363,7 @@ deleteClassProperty:
|
|||
// call(NULL),
|
||||
// construct(NULL),
|
||||
// env(NULL),
|
||||
typeofString(type->getName()),
|
||||
// typeofString(type->getName()),
|
||||
slots(new Slot[type->slotCount]),
|
||||
dynamicProperties(type->dynamic ? new DynamicPropertyMap() : NULL)
|
||||
{
|
||||
|
@ -4390,7 +4408,7 @@ deleteClassProperty:
|
|||
SimpleInstance::SimpleInstance(JS2Class *type)
|
||||
: JS2Object(SimpleInstanceKind),
|
||||
type(type),
|
||||
typeofString(type->getName()),
|
||||
// typeofString(type->getName()),
|
||||
slots(new Slot[type->slotCount]),
|
||||
dynamicProperties(type->dynamic ? new DynamicPropertyMap() : NULL)
|
||||
{
|
||||
|
|
|
@ -65,6 +65,7 @@ extern void initArrayObject(JS2Metadata *meta);
|
|||
extern void initRegExpObject(JS2Metadata *meta);
|
||||
extern void initNumberObject(JS2Metadata *meta);
|
||||
extern void initErrorObject(JS2Metadata *meta);
|
||||
extern void initBooleanObject(JS2Metadata *meta);
|
||||
|
||||
extern js2val Error_Constructor(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc);
|
||||
extern js2val EvalError_Constructor(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc);
|
||||
|
@ -281,7 +282,8 @@ public:
|
|||
// A static member is either forbidden, a variable, a hoisted variable, a constructor method, or an accessor:
|
||||
class StaticMember : public Member {
|
||||
public:
|
||||
StaticMember(MemberKind kind) : Member(kind) { }
|
||||
StaticMember(MemberKind kind) : Member(kind), forbidden(false) { }
|
||||
StaticMember(MemberKind kind, bool forbidden) : Member(kind), forbidden(forbidden) { }
|
||||
|
||||
StaticMember *cloneContent; // Used during cloning operation to prevent cloning of duplicates (i.e. once
|
||||
// a clone exists for this member it's recorded here and used for any other
|
||||
|
@ -289,7 +291,8 @@ public:
|
|||
// Also used thereafter by 'assignArguments' to initialize the singular
|
||||
// variable instantations in a parameter frame.
|
||||
|
||||
virtual StaticMember *clone() { ASSERT(false); return NULL; }
|
||||
virtual StaticMember *clone() { if (forbidden) return this; ASSERT(false); return NULL; }
|
||||
bool forbidden;
|
||||
};
|
||||
|
||||
#define FUTURE_TYPE ((JS2Class *)(-1))
|
||||
|
@ -533,7 +536,7 @@ public:
|
|||
SimpleInstance(JS2Class *type);
|
||||
|
||||
JS2Class *type; // This instance's type
|
||||
const String *typeofString; // A string to return if typeof is invoked on this instance
|
||||
// const String *typeofString; // A string to return if typeof is invoked on this instance
|
||||
Slot *slots; // A set of slots that hold this instance's fixed property values
|
||||
DynamicPropertyMap *dynamicProperties; // A set of this instance's dynamic properties, or NULL if this is a fixed instance
|
||||
|
||||
|
@ -553,7 +556,7 @@ public:
|
|||
// Environment *env; // The environment to pass to the call or construct procedure
|
||||
FunctionWrapper *fWrap;
|
||||
|
||||
const String *typeofString; // A string to return if typeof is invoked on this instance
|
||||
// const String *typeofString; // A string to return if typeof is invoked on this instance
|
||||
Slot *slots; // A set of slots that hold this instance's fixed property values
|
||||
DynamicPropertyMap *dynamicProperties; // A set of this instance's dynamic properties, or NULL if this is a fixed instance
|
||||
virtual void markChildren();
|
||||
|
@ -609,6 +612,15 @@ public:
|
|||
float64 mValue;
|
||||
};
|
||||
|
||||
// Boolean instances are Callable instances created by the Boolean class, they have an extra field
|
||||
// that contains the bool data
|
||||
class BooleanInstance : public CallableInstance {
|
||||
public:
|
||||
BooleanInstance(JS2Class *type) : CallableInstance(type), mValue(false) { }
|
||||
|
||||
bool mValue;
|
||||
};
|
||||
|
||||
// Array instances are Callable instances created by the Array class, they
|
||||
// maintain the value of the 'length' property when 'indexable' elements
|
||||
// are added.
|
||||
|
|
|
@ -252,10 +252,10 @@
|
|||
a = STRING_TO_JS2VAL(object_StringAtom);
|
||||
break;
|
||||
case SimpleInstanceKind:
|
||||
a = STRING_TO_JS2VAL(checked_cast<SimpleInstance *>(obj)->typeofString);
|
||||
a = STRING_TO_JS2VAL(checked_cast<SimpleInstance *>(obj)->type->getName());
|
||||
break;
|
||||
case CallableInstanceKind:
|
||||
a = STRING_TO_JS2VAL(checked_cast<CallableInstance *>(obj)->typeofString);
|
||||
a = STRING_TO_JS2VAL(checked_cast<CallableInstance *>(obj)->type->getName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче