From c668cc5500dff4e0295e3c5ab648688a87c80455 Mon Sep 17 00:00:00 2001 From: "rogerl%netscape.com" Date: Fri, 3 Jan 2003 00:49:29 +0000 Subject: [PATCH] Added boolean class, fixing bugs. --- js2/src/js2boolean.cpp | 122 +++++++++++++++++++++++++++++++++++ js2/src/js2engine.cpp | 9 +++ js2/src/js2metadata.cpp | 30 +++++++-- js2/src/js2metadata.h | 20 ++++-- js2/src/js2op_invocation.cpp | 4 +- 5 files changed, 173 insertions(+), 12 deletions(-) create mode 100644 js2/src/js2boolean.cpp diff --git a/js2/src/js2boolean.cpp b/js2/src/js2boolean.cpp new file mode 100644 index 00000000000..639dfe02e93 --- /dev/null +++ b/js2/src/js2boolean.cpp @@ -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 +#include +#include +#include + +#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(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(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++; + } + + } + +} +} + + diff --git a/js2/src/js2engine.cpp b/js2/src/js2engine.cpp index e8cf52430b5..54694cd8f6f 100644 --- a/js2/src/js2engine.cpp +++ b/js2/src/js2engine.cpp @@ -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; diff --git a/js2/src/js2metadata.cpp b/js2/src/js2metadata.cpp index 0422187ea7d..fa472284fcf 100644 --- a/js2/src/js2metadata.cpp +++ b/js2/src/js2metadata.cpp @@ -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) { diff --git a/js2/src/js2metadata.h b/js2/src/js2metadata.h index ef4df9eeca8..f9730a37a51 100644 --- a/js2/src/js2metadata.h +++ b/js2/src/js2metadata.h @@ -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. diff --git a/js2/src/js2op_invocation.cpp b/js2/src/js2op_invocation.cpp index 28d168b679d..89690e41fd1 100644 --- a/js2/src/js2op_invocation.cpp +++ b/js2/src/js2op_invocation.cpp @@ -252,10 +252,10 @@ a = STRING_TO_JS2VAL(object_StringAtom); break; case SimpleInstanceKind: - a = STRING_TO_JS2VAL(checked_cast(obj)->typeofString); + a = STRING_TO_JS2VAL(checked_cast(obj)->type->getName()); break; case CallableInstanceKind: - a = STRING_TO_JS2VAL(checked_cast(obj)->typeofString); + a = STRING_TO_JS2VAL(checked_cast(obj)->type->getName()); break; } }