diff --git a/js2/src/epimetheus.cpp b/js2/src/epimetheus.cpp index 272a963e1956..b11dafc4f3fe 100644 --- a/js2/src/epimetheus.cpp +++ b/js2/src/epimetheus.cpp @@ -17,7 +17,6 @@ // Copyright (C) 1998 Netscape Communications Corporation. All // Rights Reserved. - // // JS2 shell. // @@ -32,12 +31,12 @@ #include #include +#include "js2metadata.h" + #include "world.h" #include "reader.h" #include "parser.h" -#include "js2metadata.h" - #ifdef DEBUG #include "tracer.h" #include "collector.h" @@ -69,13 +68,9 @@ static void initConsole(StringPtr consoleName, #endif -using namespace JavaScript::JS2Runtime; - - JavaScript::World world; JavaScript::Arena a; - namespace JavaScript { namespace Shell { @@ -102,6 +97,9 @@ const bool showTokens = false; #define INTERPRET_INPUT 1 //#define SHOW_ICODE 1 +MetaData::GlobalObject glob(world); +MetaData::Environment env(new MetaData::SystemFrame(), &glob); +MetaData::JS2Metadata metadata(world); static int readEvalPrint(FILE *in) @@ -140,6 +138,14 @@ static int readEvalPrint(FILE *in) f.end(); stdOut << '\n'; } + + metadata.setCurrentParser(&p); + MetaData::Context cxt; + cxt.strict = true; + + metadata.ValidateStmtList(&cxt, &env, parsedStatements); + metadata.EvalStmtList(&env, MetaData::JS2Metadata::RunPhase, parsedStatements); + } clear(buffer); } catch (Exception &e) { diff --git a/js2/src/exception.cpp b/js2/src/exception.cpp index dc39c9194ae1..417d709e4fee 100644 --- a/js2/src/exception.cpp +++ b/js2/src/exception.cpp @@ -52,6 +52,8 @@ static const char *const kindStrings[] = { "Uncaught exception error", // uncaught exception error "Semantic error", // semantic error "User exception", // 'throw' from user code + "Definition error", // a monkey is a small cup of milk + "Bad Value error", // bad value, no biscuit }; // Return a null-terminated string describing the exception's kind. diff --git a/js2/src/exception.h b/js2/src/exception.h index bfb40ff2f496..99b69343f645 100644 --- a/js2/src/exception.h +++ b/js2/src/exception.h @@ -56,7 +56,9 @@ namespace JavaScript typeError, uncaughtError, semanticError, - userException + userException, + definitionError, + badValueError }; Kind kind; // The exception's kind diff --git a/js2/src/hash.h b/js2/src/hash.h index 2b5d6a877a97..6150e46cc9a0 100644 --- a/js2/src/hash.h +++ b/js2/src/hash.h @@ -182,7 +182,9 @@ namespace JavaScript { GenericHashEntry **bp = ht.buckets + h; Entry *e; - while ((e = static_cast(*bp)) != 0 && !(e->keyHash == kh && e->data == key)) + while ((e = static_cast(*bp)) != 0 + && !(e->keyHash == kh + && e->data == key)) bp = &e->next; entry = e; backpointer = bp; diff --git a/js2/src/js2eval.cpp b/js2/src/js2eval.cpp new file mode 100644 index 000000000000..4cc4478f3885 --- /dev/null +++ b/js2/src/js2eval.cpp @@ -0,0 +1,101 @@ + +/* -*- 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 + // Turn off warnings about identifiers too long in browser information +#pragma warning(disable: 4786) +#pragma warning(disable: 4711) +#pragma warning(disable: 4710) +#endif + + +#include "js2metadata.h" + + +#include "jsstddef.h" +#include +#include +#include +#include +#include "jstypes.h" +#include "jsarena.h" +#include "jsutil.h" +#include "jsprf.h" +#include "jsapi.h" +#include "jsatom.h" +#include "jscntxt.h" +#include "jsdbgapi.h" +#include "jsemit.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jslock.h" +#include "jsobj.h" +#include "jsparse.h" +#include "jsscope.h" +#include "jsscript.h" + +namespace JavaScript { +namespace MetaData { + + + JSRuntime *gJavaScriptRuntime; + JSContext *gJavaScriptContext; + JSObject *gJavaScriptGlobalObject; + JSClass gJavaScriptGlobalClass = { "MyClass", 0, JS_PropertyStub, JS_PropertyStub, + JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, + JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub }; + + + void JS2Metadata::initializeMonkey( ) + { + gJavaScriptRuntime = JS_NewRuntime( 1000000L ); + if (gJavaScriptRuntime) { + gJavaScriptContext = JS_NewContext( gJavaScriptRuntime, 8192 ); + if (gJavaScriptContext) { + gJavaScriptGlobalObject = JS_NewObject(gJavaScriptContext, &gJavaScriptGlobalClass, NULL, NULL); + if (gJavaScriptGlobalObject) + JS_SetGlobalObject(gJavaScriptContext, gJavaScriptGlobalObject); + } + } + } + + jsval JS2Metadata::execute(String *str) + { + jsval retval; + JS_EvaluateUCScript(gJavaScriptContext, gJavaScriptGlobalObject, str->c_str(), str->length(), "file", 1, &retval); + return retval; + } + +}; // namespace MetaData +}; // namespace Javascript \ No newline at end of file diff --git a/js2/src/js2metadata.cpp b/js2/src/js2metadata.cpp new file mode 100644 index 000000000000..ff9c95705d8b --- /dev/null +++ b/js2/src/js2metadata.cpp @@ -0,0 +1,426 @@ +/* -*- 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 + // Turn off warnings about identifiers too long in browser information +#pragma warning(disable: 4786) +#pragma warning(disable: 4711) +#pragma warning(disable: 4710) +#endif + + +#include + + +#include "js2metadata.h" + + + +namespace JavaScript { +namespace MetaData { + + + /* + * Validate the linked list of statement nodes beginning at 'p' + */ + void JS2Metadata::ValidateStmtList(Context *cxt, Environment *env, StmtNode *p) { + while (p) { + ValidateStmt(cxt, env, p); + p = p->next; + } + } + + /* + * Validate an individual statement 'p', including it's children + */ + void JS2Metadata::ValidateStmt(Context *cxt, Environment *env, StmtNode *p) { + switch (p->getKind()) { + case StmtNode::block: + case StmtNode::group: + { + BlockStmtNode *b = checked_cast(p); + ValidateStmtList(cxt, env, b->statements); + } + break; + case StmtNode::label: + { + LabelStmtNode *l = checked_cast(p); + ValidateStmt(cxt, env, l->stmt); + } + break; + case StmtNode::Var: + case StmtNode::Const: + { + VariableStmtNode *vs = checked_cast(p); + + ValidateExpression(cxt, env, vs->attributes); + EvalAttributeExpression(env, CompilePhase, vs->attributes); + + + VariableBinding *v = vs->bindings; + Frame *regionalFrame = env->getRegionalFrame(); + while (v) { + ValidateTypeExpression(v->type); + + if (cxt->strict && ((regionalFrame->kind == Frame::GlobalObject) + || (regionalFrame->kind == Frame::Function)) + && (p->getKind() == StmtNode::Var) // !immutable + && (vs->attributes == NULL) + && (v->type == NULL)) { + defineHoistedVar(env, *v->name, p); + } + else { + } + + v = v->next; + } + } + break; + case StmtNode::expression: + { + ExprStmtNode *e = checked_cast(p); + ValidateExpression(cxt, env, e->expr); + } + break; + } // switch (p->getKind()) + } + + void JS2Metadata::ValidateExpression(Context *cxt, Environment *env, ExprNode *p) + { + switch (p->getKind()) { + case ExprNode::juxtapose: + break; + } // switch (p->getKind()) + } + + // Evaluate the attribute expression rooted at p. + // An attribute expression can only be a list of 'juxtaposed' attribute elements + Attribute *JS2Metadata::EvalAttributeExpression(Environment *env, Phase phase, ExprNode *p) + { + switch (p->getKind()) { + case ExprNode::boolean: + if (checked_cast(p)->value) + return new TrueAttribute(); + else + return new FalseAttribute(); + case ExprNode::juxtapose: + { + BinaryExprNode *j = checked_cast(p); + Attribute *a = EvalAttributeExpression(env, phase, j->op1); + if (a && (a->kind == FalseKind)) + return a; + Attribute *b = EvalAttributeExpression(env, phase, j->op2); + try { + return Attribute::combineAttributes(a, b); + } + catch (char *err) { + reportError(Exception::badValueError, err, p->pos); + } + } + break; + + default: + { + // anything else (just references of one kind or another) must + // be compile-time constant values that resolve to namespaces + jsval av = EvalExpression(env, CompilePhase, p); + if (!JSVAL_IS_OBJECT(av)) + reportError(Exception::badValueError, "Namespace expected in attribute", p->pos); + } + break; + + } // switch (p->getKind()) + return NULL; + } + + // a is not false + Attribute *Attribute::combineAttributes(Attribute *a, Attribute *b) + { + if (b && (b->kind == FalseKind)) { + if (a) delete a; + return b; + } + if (!a || (a->kind == TrueKind)) { + if (a) delete a; + return b; + } + if (!b || (b->kind == TrueKind)) { + if (b) delete b; + return a; + } + if (a->kind == NamespaceKind) { + if (a == b) { + delete b; + return a; + } + Namespace *na = checked_cast(a); + if (b->kind == NamespaceKind) { + Namespace *nb = checked_cast(b); + CompoundAttribute *c = new CompoundAttribute(); + c->addNamespace(na); + c->addNamespace(nb); + delete a; + delete b; + return (Attribute *)c; + } + else { + ASSERT(b->kind == CompoundKind); + CompoundAttribute *cb = checked_cast(b); + cb->addNamespace(na); + delete a; + return b; + } + } + else { + // Both a and b are compound attributes. Ensure that they have no conflicting contents. + ASSERT((a->kind == CompoundKind) && (b->kind == CompoundKind)); + CompoundAttribute *ca = checked_cast(a); + CompoundAttribute *cb = checked_cast(b); + if ((ca->memberMod != NoModifier) && (cb->memberMod != NoModifier) && (ca->memberMod != cb->memberMod)) + throw("Illegal combination of member modifier attributes"); + if ((ca->overrideMod != NoOverride) && (cb->overrideMod != NoOverride) && (ca->overrideMod != cb->overrideMod)) + throw("Illegal combination of override attributes"); + for (NamespaceListIterator i = cb->namespaces->begin(), end = cb->namespaces->end(); (i != end); i++) + ca->addNamespace(*i); + ca->xplicit |= cb->xplicit; + ca->dynamic |= cb->dynamic; + if (ca->memberMod == NoModifier) + ca->memberMod = cb->memberMod; + if (ca->overrideMod == NoModifier) + ca->overrideMod = cb->overrideMod; + ca->prototype |= cb->prototype; + ca->unused |= cb->unused; + delete b; + return a; + } + } + + // add the namespace to our list, but only if it's not there already + void CompoundAttribute::addNamespace(Namespace *n) + { + for (NamespaceListIterator i = namespaces->begin(), end = namespaces->end(); (i != end); i++) + if (*i == n) + return; + namespaces->push_back(n); + } + + + jsval JS2Metadata::EvalStmt(Environment *env, Phase phase, StmtNode *p) + { + jsval retval = JSVAL_VOID; + switch (p->getKind()) { + case StmtNode::block: + case StmtNode::group: + { + BlockStmtNode *b = checked_cast(p); + retval = EvalStmtList(env, phase, b->statements); + } + break; + case StmtNode::label: + { + LabelStmtNode *l = checked_cast(p); + retval = EvalStmt(env, phase, l->stmt); + } + break; + case StmtNode::Var: + case StmtNode::Const: + { + VariableStmtNode *vs = checked_cast(p); + + VariableBinding *v = vs->bindings; + while (v) { + + v = v->next; + } + } + break; + case StmtNode::expression: + { + ExprStmtNode *e = checked_cast(p); + retval = EvalExpression(env, phase, e->expr); + } + break; + default: + NOT_REACHED("Not Yet Implemented"); + } // switch (p->getKind()) + return retval; + } + + // Evaluate the expression rooted at p. + jsval JS2Metadata::EvalExpression(Environment *env, Phase phase, ExprNode *p) + { + String str; + switch (p->getKind()) { + case ExprNode::boolean: + if (checked_cast(p)->value) + str += "true" ; + else + str += "false"; + break; + } + return execute(&str); + } + + /* + * Evaluate the linked list of statement nodes beginning at 'p' + */ + jsval JS2Metadata::EvalStmtList(Environment *env, Phase phase, StmtNode *p) { + jsval retval = JSVAL_VOID; + while (p) { + retval = EvalStmt(env, phase, p); + p = p->next; + } + return retval; + } + + + void JS2Metadata::ValidateTypeExpression(ExprNode *e) + { + } + + + // returns the most specific regional frame. + Frame *Environment::getRegionalFrame() + { + Frame *pf = firstFrame; + Frame *prev = NULL; + while (pf->kind == Frame::Block) { + prev = pf; + pf = pf->nextFrame; + } + if (pf->nextFrame && (pf->kind == Frame::Class)) + pf = prev; + return pf; + } + + // Define a hoisted var in the current frame (either Global or a Function) + void JS2Metadata::defineHoistedVar(Environment *env, const StringAtom &id, StmtNode *p) + { + QualifiedName qName(&publicNamespace, id); + Frame *regionalFrame = env->getRegionalFrame(); + ASSERT((env->getTopFrame()->kind == Frame::GlobalObject) || (env->getTopFrame()->kind == Frame::Function)); + + // run through all the existing bindings, both read and write, to see if this + // variable already exists. + StaticBindingIterator b, end; + bool existing = false; + for (b = regionalFrame->staticReadBindings.lower_bound(id), + end = regionalFrame->staticReadBindings.upper_bound(id); (b != end); b++) { + if (b->second->qname == qName) { + if (b->second->content->kind != StaticMember::HoistedVariable) + reportError(Exception::definitionError, "Duplicate definition {0}", p->pos, id); + else { + existing = true; + break; + } + } + } + for (b = regionalFrame->staticWriteBindings.lower_bound(id), + end = regionalFrame->staticWriteBindings.upper_bound(id); (b != end); b++) { + if (b->second->qname == qName) { + if (b->second->content->kind != StaticMember::HoistedVariable) + reportError(Exception::definitionError, "Duplicate definition {0}", p->pos, id); + else { + existing = true; + break; + } + } + } + if (!existing) { + if (regionalFrame->kind == Frame::GlobalObject) { + GlobalObject *gObj = checked_cast(regionalFrame); + DynamicPropertyIterator dp = gObj->dynamicProperties.find(id); + if (dp != gObj->dynamicProperties.end()) + reportError(Exception::definitionError, "Duplicate definition {0}", p->pos, id); + } + // XXX ok to use same binding in read & write maps? + StaticBinding *sb = new StaticBinding(qName, new HoistedVar()); + const StaticBindingMap::value_type e(id, sb); + + // XXX ok to use same value_type in different multimaps? + regionalFrame->staticReadBindings.insert(e); + regionalFrame->staticWriteBindings.insert(e); + } + //else A hoisted binding of the same var already exists, so there is no need to create another one + } + + JS2Metadata::JS2Metadata(World &world) : + publicNamespace(world.identifiers["public"]) + { + initializeMonkey(); + } + + + /* + * Throw an exception of the specified kind, indicating the position 'pos' and + * attaching the given message. If 'arg' is specified, replace {0} in the message + * with the argument value. [This is intended to be widened into a more complete + * argument handling scheme]. + */ + void JS2Metadata::reportError(Exception::Kind kind, char *message, size_t pos, const char *arg) + { + const char16 *lineBegin; + const char16 *lineEnd; + String x = widenCString(message); + if (arg) { + // XXX handle multiple occurences and extend to {1} etc. + uint32 a = x.find(widenCString("{0}")); + x.replace(a, 3, widenCString(arg)); + } + uint32 lineNum = mParser->lexer.reader.posToLineNum(pos); + size_t linePos = mParser->lexer.reader.getLine(lineNum, lineBegin, lineEnd); + ASSERT(lineBegin && lineEnd && linePos <= pos); + throw Exception(kind, x, mParser->lexer.reader.sourceLocation, + lineNum, pos - linePos, pos, lineBegin, lineEnd); + } + + inline char narrow(char16 ch) { return char(ch); } + void JS2Metadata::reportError(Exception::Kind kind, char *message, size_t pos, const String& name) + { + std::string str(name.length(), char()); + std::transform(name.begin(), name.end(), str.begin(), narrow); + reportError(kind, message, pos, str.c_str()); + } + + CompoundAttribute::CompoundAttribute() : Attribute(CompoundKind), + namespaces(NULL), xplicit(false), dynamic(false), + memberMod(NoModifier), overrideMod(NoOverride), prototype(false), + unused(false) + { + } + + + +}; // namespace MetaData +}; // namespace Javascript \ No newline at end of file diff --git a/js2/src/js2metadata.h b/js2/src/js2metadata.h index 7243669811f0..8b1dcaaddb1d 100644 --- a/js2/src/js2metadata.h +++ b/js2/src/js2metadata.h @@ -32,10 +32,13 @@ * file under either the NPL or the GPL. */ +#include "jsapi.h" #include "world.h" #include "utilities.h" +#include "parser.h" +#include namespace JavaScript { namespace MetaData { @@ -43,7 +46,10 @@ namespace MetaData { // forward definitions: class JS2Class; -typedef uint32 js2val; +class StaticBinding; +class Environment; +class Context; +typedef jsval js2val; typedef void (Invokable)(); typedef Invokable Callor; @@ -56,16 +62,39 @@ class JS2Object { public: }; -class Namespace { +class Attribute { public: + enum AttributeKind { TrueKind, FalseKind, NamespaceKind, CompoundKind } kind; + enum MemberModifier { NoModifier, Static, Constructor, Operator, Abstract, Virtual, Final}; + enum OverrideModifier { NoOverride, DoOverride, DontOverride, OverrideUndefined }; + + + Attribute(AttributeKind kind) : kind(kind) { } + + static Attribute *combineAttributes(Attribute *a, Attribute *b); + +#ifdef DEBUG + virtual void uselessVirtual() { } // want the checked_cast stuff to work, so need a virtual function +#endif +}; + +// A Namespace (is also an attribute) +class Namespace : public Attribute { +public: + Namespace(StringAtom &name) : Attribute(NamespaceKind), name(name) { } + StringAtom &name; // The namespace's name used by toString }; class QualifiedName { public: - Namespace nameSpace; // The namespace qualifier - StringAtom &id; // The name + QualifiedName(Namespace *nameSpace, const StringAtom &id) : nameSpace(nameSpace), id(id) { } + + bool operator ==(const QualifiedName &b) { return (nameSpace == b.nameSpace) && (id == b.id); } + + Namespace *nameSpace; // The namespace qualifier + const StringAtom &id; // The name }; @@ -92,21 +121,25 @@ class Signature { bool returnType; // The type of this function's result }; +// A static member is either forbidden, a variable, a hoisted variable, a constructor method, or an accessor: class StaticMember { public: + enum StaticMemberKind { Forbidden, Variable, HoistedVariable, ConstructorMethod, Accessor } kind; }; class Variable : public StaticMember { public: JS2Class *type; // Type of values that may be stored in this variable - Object_Uninit_Future value; // This variable's current value; future if the variable has not been declared yet; + js2val value; // This variable's current value; future if the variable has not been declared yet; // uninitialised if the variable must be written before it can be read bool immutable; // true if this variable's value may not be changed once set }; class HoistedVar : public StaticMember { public: + HoistedVar() : value(JSVAL_VOID), hasFunctionInitializer(false) { } js2val value; // This variable's current value + bool hasFunctionInitializer; // true if this variable was created by a function statement }; class StaticMethod : public StaticMember { @@ -124,12 +157,20 @@ public: }; +// DYNAMICPROPERTY record describes one dynamic property of one (prototype or class) instance. +typedef std::map DynamicPropertyMap; +typedef DynamicPropertyMap::iterator DynamicPropertyIterator; - +// A STATICBINDING describes the member to which one qualified name is bound in a frame. Multiple +// qualified names may be bound to the same member in a frame, but a qualified name may not be +// bound to multiple members in a frame (except when one binding is for reading only and +// the other binding is for writing only). class StaticBinding { public: + StaticBinding(QualifiedName &qname, StaticMember *content) : qname(qname), content(content), xplicit(false) { } + QualifiedName qname; // The qualified name bound by this binding - StaticMember content; // The member to which this qualified name was bound + StaticMember *content; // The member to which this qualified name was bound bool xplicit; // true if this binding should not be imported into the global scope by an import statement }; @@ -161,24 +202,41 @@ public: class InstanceBinding { public: - QualifiedName qname; // The qualified name bound by this binding + QualifiedName qname; // The qualified name bound by this binding InstanceMember *content; // The member to which this qualified name was bound }; -class StaticBindingMap { -public: -}; + +// A StaticBindingMap maps names to a list of StaticBindings. Each StaticBinding in the list +// will have the same QualifiedName.name, but (potentially) different QualifiedName.namespace values +typedef std::multimap StaticBindingMap; +typedef StaticBindingMap::iterator StaticBindingIterator; class InstanceBindingMap { public: }; -class JS2Class { +// A frame contains bindings defined at a particular scope in a program. A frame is either the top-level system frame, +// a global object, a package, a function frame, a class, or a block frame +class Frame { +public: + enum Plurality { Singular, Plural }; + enum FrameKind { GlobalObject, Package, Function, Class, Block }; + + StaticBindingMap staticReadBindings; // Map of qualified names to readable static members defined in this frame + StaticBindingMap staticWriteBindings; // Map of qualified names to writable static members defined in this frame + + FrameKind kind; // [rather than use RTTI (in general)] + Frame *nextFrame; +#ifdef DEBUG + virtual void uselessVirtual() { } // want the checked_cast stuff to work, so need a virtual function +#endif +}; + + +class JS2Class : public Frame { public: - StaticBindingMap staticReadBindings; // Map of qualified names to readable static members defined in this class - StaticBindingMap staticWriteBindings; // Map of qualified names to writable static members defined in this class - InstanceBindingMap instanceReadBindings; // Map of qualified names to readable instance members defined in this class InstanceBindingMap instanceWriteBindings; // Map of qualified names to writable instance members defined in this class @@ -189,7 +247,7 @@ public: JS2Class *super; // This class's immediate superclass or null if none JS2Object *prototype; // An object that serves as this class's prototype for compatibility with ECMAScript 3; may be null - Namespace privateNamespace; // This class's private namespace + Namespace *privateNamespace; // This class's private namespace bool dynamic; // true if this class or any of its ancestors was defined with the dynamic attribute bool primitive; // true if this class was defined with the primitive attribute @@ -200,8 +258,49 @@ public: }; +class GlobalObject : public Frame { +public: + GlobalObject(World &world) : internalNamespace(new Namespace(world.identifiers["internal"])) { } + + Namespace *internalNamespace; // This global object's internal namespace + DynamicPropertyMap dynamicProperties; // A set of this global object's dynamic properties +}; +// A SLOT record describes the value of one fixed property of one instance. +class Slot { +public: + InstanceVariable *id; // The instance variable whose value this slot carries + js2val value; // This fixed property's current value; uninitialised if the fixed property is an uninitialised constant +}; + +// Instances of non-dynamic classes are represented as FIXEDINSTANCE records. These instances can contain only fixed properties. +class FixedInstance { +public: + JS2Class *type; // This instance's type + Invokable *call; // A procedure to call when this instance is used in a call expression + Invokable *construct; // A procedure to call when this instance is used in a new expression + Environment *env; // The environment to pass to the call or construct procedure + StringAtom &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 +}; + +// Instances of dynamic classes are represented as DYNAMICINSTANCE records. These instances can contain fixed and dynamic properties. +class DynamicInstance { +public: + JS2Class *type; // This instance's type + Invokable *call; // A procedure to call when this instance is used in a call expression + Invokable *construct; // A procedure to call when this instance is used in a new expression + Environment *env; // The environment to pass to the call or construct procedure + StringAtom &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 +}; + +// MULTINAME is the semantic domain of sets of qualified names. Multinames are used internally in property lookup. +class Multiname { +public: +}; class LexicalReference { // A LEXICALREFERENCE tuple has the fields below and represents an lvalue that refers to a variable with one @@ -227,6 +326,21 @@ public: // example above) }; + +class NamedArgument { +public: + StringAtom &name; // This argument's name + js2val value; // This argument's value +}; + +// An ARGUMENTLIST describes the arguments (other than this) passed to a function. +class ArgumentList { +public: + JS2Object *positional; // Ordered list of positional arguments + NamedArgument *named; // Set of named arguments +}; + + class BracketReference { // A BRACKETREFERENCE tuple has the fields below and represents an lvalue that refers to the result of // applying the [] operator to the base object with the given arguments. BRACKETREFERENCE tuples arise from evaluating @@ -239,6 +353,115 @@ public: }; +// The top-level frame containing predefined constants, functions, and classes. +class SystemFrame : public Frame { +public: +}; + +// Frames holding bindings for invoked functions +class FunctionFrame : public Frame { +public: + Plurality plurality; + JS2Object *thisObject; // The value of this; none if this function doesn't define this; + // XXX // inaccessible if this function defines this but the value is not + // available because this function hasn't been called yet + bool prototype; // true if this function is not an instance method but defines this anyway +}; + +class BlockFrame : public Frame { +public: + Plurality plurality; +}; + +// Environments contain the bindings that are visible from a given point in the source code. An ENVIRONMENT is +// a list of two or more frames. Each frame corresponds to a scope. More specific frames are listed first +// -each frame's scope is directly contained in the following frame's scope. The last frame is always the +// SYSTEMFRAME. The next-to-last frame is always a PACKAGE or GLOBAL frame. +class Environment { +public: + Environment(SystemFrame *systemFrame, Frame *nextToLast) : firstFrame(nextToLast) { nextToLast->nextFrame = systemFrame; } + + Frame *getRegionalFrame(); + Frame *getTopFrame() { return firstFrame; } +private: + Frame *firstFrame; +}; + +typedef std::vector NamespaceList; +typedef NamespaceList::iterator NamespaceListIterator; + +// A CONTEXT carries static information about a particular point in the source program. +class Context { +public: + bool strict; // true if strict mode is in effect + Namespace *openNamespaces; // The set of namespaces that are open at this point. + // The public namespace is always a member of this set. +}; + +// The 'true' attribute +class TrueAttribute : public Attribute { +public: + TrueAttribute() : Attribute(TrueKind) { } +}; + +// The 'false' attribute +class FalseAttribute : public Attribute { +public: + FalseAttribute() : Attribute(FalseKind) { } +}; + +// Compound attribute objects are all values obtained from combining zero or more syntactic attributes +// that are not Booleans or single namespaces. +class CompoundAttribute : public Attribute { +public: + CompoundAttribute(); + void addNamespace(Namespace *n); + + NamespaceList *namespaces; // The set of namespaces contained in this attribute + bool xplicit; // true if the explicit attribute has been given + bool dynamic; // true if the dynamic attribute has been given + MemberModifier memberMod; // if one of these attributes has been given; none if not. + OverrideModifier overrideMod; // if the override attribute with one of these arguments was given; + // true if the attribute override without arguments was given; none if the override attribute was not given. + bool prototype; // true if the prototype attribute has been given + bool unused; // true if the unused attribute has been given +}; + +class JS2Metadata { +public: + + enum Phase { CompilePhase, RunPhase }; + + JS2Metadata(World &world); + + void setCurrentParser(Parser *parser) { mParser = parser; } + + void ValidateTypeExpression(ExprNode *e); + void ValidateStmtList(Context *cxt, Environment *env, StmtNode *p); + void ValidateStmt(Context *cxt, Environment *env, StmtNode *p); + void defineHoistedVar(Environment *env, const StringAtom &id, StmtNode *p); + void ValidateExpression(Context *cxt, Environment *env, ExprNode *p); + + jsval EvalExpression(Environment *env, Phase phase, ExprNode *p); + Attribute *EvalAttributeExpression(Environment *env, Phase phase, ExprNode *p); + jsval EvalStmtList(Environment *env, Phase phase, StmtNode *p); + jsval EvalStmt(Environment *env, Phase phase, StmtNode *p); + + void reportError(Exception::Kind kind, char *message, size_t pos, const char *arg = NULL); + void reportError(Exception::Kind kind, char *message, size_t pos, const String& name); + + + void initializeMonkey(); + jsval execute(String *str); + + + // The one and only 'public' namespace + Namespace publicNamespace; // XXX is this the right place for this ??? + + + Parser *mParser; // used for error reporting + +}; }; // namespace MetaData diff --git a/js2/src/numerics.cpp b/js2/src/numerics.cpp index c7712a1f00cf..00ca4e98a78a 100644 --- a/js2/src/numerics.cpp +++ b/js2/src/numerics.cpp @@ -36,13 +36,19 @@ #include #include "numerics.h" #include "parser.h" -//#include "js2runtime.h" + +#ifdef DIKDIK +#include "js2runtime.h" +#endif #include "fdlibm_ns.h" namespace JS = JavaScript; using namespace JS; + +#ifdef DIKDIK using namespace JS::JS2Runtime; +#endif // // Portable double-precision floating point to string and back conversions diff --git a/js2/src/systemtypes.h b/js2/src/systemtypes.h index 26891cf39b95..eeead7e6fb28 100644 --- a/js2/src/systemtypes.h +++ b/js2/src/systemtypes.h @@ -96,7 +96,6 @@ typedef float float32; #define IS_LITTLE_ENDIAN #endif - // basicAlignment is the maximum alignment required by any native type. An // object aligned to a multiple of basicAlignment can hold any native type. // malloc should return a pointer whose lgBasicAlignment least significant bits diff --git a/js2/src/winbuild/Epimetheus/Epimetheus.dsp b/js2/src/winbuild/Epimetheus/Epimetheus.dsp index 4764ebe9e321..779d70276b39 100644 --- a/js2/src/winbuild/Epimetheus/Epimetheus.dsp +++ b/js2/src/winbuild/Epimetheus/Epimetheus.dsp @@ -39,17 +39,18 @@ RSC=rc.exe # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\js\src" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "XP_PC" /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib js32.lib /nologo /subsystem:console /machine:I386 !ELSEIF "$(CFG)" == "Epimetheus - Win32 Debug" @@ -62,17 +63,18 @@ LINK32=link.exe # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 # PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GR /GX /ZI /Od /I "..\..\..\..\js\src" /D "_DEBUG" /D "DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "XP_PC" /FR /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 js32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\..\js\src\debug" !ENDIF @@ -101,6 +103,14 @@ SOURCE=..\..\hash.cpp # End Source File # Begin Source File +SOURCE=..\..\js2eval.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\js2metadata.cpp +# End Source File +# Begin Source File + SOURCE=..\..\lexer.cpp # End Source File # Begin Source File @@ -153,6 +163,14 @@ SOURCE=..\..\hash.h # End Source File # Begin Source File +SOURCE=..\..\js2metadata.h +# End Source File +# Begin Source File + +SOURCE=..\..\js2value.h +# End Source File +# Begin Source File + SOURCE=..\..\lexer.h # End Source File # Begin Source File diff --git a/js2/src/world.h b/js2/src/world.h index 89bdf2993a23..a4568b566272 100644 --- a/js2/src/world.h +++ b/js2/src/world.h @@ -72,9 +72,11 @@ namespace JavaScript { StringAtom &operator[](const char *s) {return operator[](widenCString(s));} }; +#ifdef DIKDIK namespace JS2Runtime { class Context; } +#endif class World { public: @@ -82,6 +84,7 @@ namespace JavaScript { World(); +#ifdef DIKDIK std::vector contextList; /* Random number generator state, used by jsmath.c. */ @@ -91,6 +94,8 @@ namespace JavaScript { int64 rngMask; int64 rngSeed; float64 rngDscale; +#endif + }; } #endif