} // JStringObject constructor // Only used when creating stringPrototype. private JStringObject(JObject prototype, string value) : base(prototype, null, "String") { this.value = value; } // JStringObject constructor
} // DefineBuiltinGlobals // For each public static method of the specified type, create a // function in the given prototype object. private static void RegisterBuiltins(Type impType, JObject proto) { CachedTypeInfo typeInfo = CachedTypeInfo.GetInfoForType(impType, true); IDictionaryEnumerator enumerator = typeInfo.members.GetEnumerator(); while (enumerator.MoveNext()) if (enumerator.Value is MethodInfo) { // Non-overloaded method. Register a function glue // object. JFunctionObject func = new JFunctionStaticGlue( typeInfo, (string) enumerator.Key, enumerator.Value ); proto.Put((string)enumerator.Key, func); } else if (enumerator.Value is MethodBase[]) { // Overloaded method. Register a function glue // object. JFunctionObject func = new JFunctionStaticGlue( typeInfo, (string) enumerator.Key, enumerator.Value ); proto.Put((string)enumerator.Key, func); } } // RegisterBuiltins
} // CanPut // Perform the [[Construct]] operation on this object. // // The JObject implementation simply throws TypeError, per the ECMAScript // spec. JFunctionObject overrides it. public virtual object Construct(JObject this_, params object[] args) { throw new TypeError("[[Construct]] invoked for a non-function object"); } // Construct
} // JBooleanObject constructor // Only used when creating booleanPrototype. private JBooleanObject(JObject prototype, bool value) : base(prototype, null, "Boolean") { this.value = value; } // JBooleanObject constructor
} // LookupProperty // Perform the [[Construct]] operation on this object. public override object Construct(JObject this_, params object[] args) { if (constructImp != null) { JObject newObj = new JObject(InstancePrototype, this, "Object"); object temp = constructImp(newObj, args); if (JObject.Typeof(temp) == "object") return temp; else return newObj; } else throw new TypeError("Construct called for an object with no [[Construct]] operation"); } // Construct
// HACK snewman 7/26/01: ensure that the type analysis in these methods is // complete, e.g. that "value is double" will fire for all numeric values. // Might need to add additional tests for 64-bit int, for example. // Convert the given value to a primitive type. public static object ToPrimitive(object value, JObject.ValueHintType hint) { // If the value is already a JavaScript primitive type, just return it. if (JObject.IsPrimitive(value)) return value; // Otherwise, convert it to a primitive. JObject asObj = value as JObject; if (asObj != null) return asObj.DefaultValue(hint); else throw new TypeError("attempt to convert non-JavaScript object to primitive"); } // ToPrimitive
} // hasOwnProperty public static bool isPrototypeOf(JObject _this, object v) { JObject vObj = v as JObject; if (vObj == null) return false; while (true) { vObj = vObj.proto; if (vObj == null) return false; if (vObj == _this) return true; } } // isPrototypeOf
// Similar to CompileAndLoad, but the caller supplies the global-variable // object. Used for running "eval" code. // // HACK snewman 8/26/01: this is far from a complete implementation of // "eval". For one thing, there's no way to supply the caller's // activation frame. public static Type CompileAndLoadForEval( TextReader input, string progClassName, string inputFileLabel, string fileNameBase, JObject globals ) { string dllFileName; CompileToDLL( input, progClassName, inputFileLabel, fileNameBase, true, out dllFileName ); Assembly a = Assembly.LoadFrom(dllFileName); Type theType = a.GetType(progClassName); return theType; // ConstructorInfo constructor = theType.GetConstructor(joTypeArray); // object progInstance = constructor.Invoke(new object[1] {globals}); // return (IJANETProgram)progInstance; } // CompileAndLoadForEval
} // toLocaleString public static JObject valueOf(JObject _this) { return _this; } // valueOf
} // valueOf public static bool hasOwnProperty(JObject _this, object v) { string vStr = JConvert.ToString(v); return _this.HasOwnProperty(vStr); } // hasOwnProperty
} // toString public static string toLocaleString(JObject _this) { return toString(_this); } // toLocaleString
public static string toString(JObject _this) { return "[object " + _this.className + "]"; } // toString
} // JFunctionStaticGlue constructor // Perform the [[Call]] operation on this object. public override object Call(JObject this_, params object[] args) { object[] augmentedArgs = new object[args.Length+1]; augmentedArgs[0] = this_; Array.Copy(args, 0, augmentedArgs, 1, args.Length); return typeInfo.InvokeMethod(null, methodName, augmentedArgs); } // Call
} // WithTypeof // Execute a call expression where the function to be called is specified // by an identifier inside one or more with scopes. We determine the // actual function or method as for WithPut. // // This method may alter the args array (performing type conversions on // arguments as needed to match the method parameters). public static object WithCall( JObject lhs, string id, object[] withs, params object[] args ) { for (int i=0; i<withs.Length; i++) if (HasProperty(withs[i], id)) return CallMethod(withs[i], id, args); return Call(lhs.Get(id), args); } // WithCall
} // isPrototypeOf public static bool propertyIsEnumerable(JObject _this, object v) { string vStr = JConvert.ToString(v); JProperty prop; return _this.LookupProperty(vStr, out prop) && (prop.attributes & JProperty.AttrFlags.dontEnum) == 0; } // propertyIsEnumerable
} // WrapException // Create a JObject with one property. The property's name // is "id" and its value is the given exception object. public static JObject CreateCatchScope(Exception exception, string id) { object unwrapped; if (exception is WrappedException) unwrapped = ((WrappedException)exception).obj; else unwrapped = exception; JObject obj = new JObject(null, null, "CatchScope"); obj.Put(id, unwrapped); return obj; } // CreateCatchScope
} // TypeofProperty // Execute a "new" expression public static object New(object constructor, params object[] args) { JFunctionObject cFunc = constructor as JFunctionObject; if (cFunc == null) throw new TypeError("operator new invoked on a non-function"); JObject newObj = new JObject( JObject.ObjectPrototype, cFunc, "Object" ); return cFunc.Construct(newObj, args); } // New
} // JFunctionObject constructor // Like the previous constructor, but allows the caller to explicitly // supply the prototype object for objects created using this function. public JFunctionObject( JFunctionImp callImp, JFunctionImp constructImp, object[] scopes, JObject instanceProto ) : this(callImp, constructImp, scopes) { this.instanceProto = instanceProto; } // JFunctionObject constructor
} // BoolTest // Create a new object from a literal expression. There should be // an even number of arguments, consisting alternately of property // names and property values for the object. public static JObject LiteralObject(params object[] args) { JObject obj = new JObject(JObject.ObjectPrototype, null, "Object"); for (int i=0; i<args.Length; i += 2) obj.Put((string)(args[i]), args[i+1]); return obj; } // LiteralObject
} // Construct // Perform the [[Call]] operation on this object. public override object Call(JObject this_, params object[] args) { if (callImp != null) return callImp(this_, args); else throw new TypeError("Call called for an object with no [[Call]] operation"); } // Call
} // LiteralArray // Read an identifier value, searching one or more "with" scopes. // We first search for id in each object in the withs array, starting // with the last entry in the array. If any object in the array has // a property of the given name, we return the property value. Otherwise, // if lhs has a property of that name, we return its value. If no // object had a property of the given name, we return undefined. public static object WithGet(JObject lhs, string id, params object[] withs) { for (int i=0; i<withs.Length; i++) { object value = GetProperty(withs[i], id); if (!(value is JUndefinedObject)) return value; } return lhs.Get(id); } // WithGet
} // ObjectConstructor // Construct a JObject with the given prototype, constructor link, and // class name. public JObject(JObject proto, object constructor, string className) { this.proto = proto; this.constructor = constructor; this.className = className; this.props = new System.Collections.Hashtable(); } // JObject constructor
} // WithGet // Set an identifier value, searching one or more "with" scopes. // We first search for id in each object in the withs array, starting // with the last entry in the array. If any object in the array has // a property of the given name, we update that property value. Otherwise, // we call lhs.Put(id, value). public static object WithPut( JObject lhs, string id, object value, params object[] withs ) { for (int i=0; i<withs.Length; i++) if (HasProperty(withs[i], id)) return AssignProperty(withs[i], id, value); return lhs.Put(id, value); } // WithPut
} // Construct // Perform the [[Call]] operation on this object. // // The JObject implementation simply throws TypeError, per the ECMAScript // spec. JFunctionObject overrides it. public virtual object Call(JObject this_, params object[] args) { throw new TypeError("[[call]] invoked for a non-function object"); } // Call
} // WithPut // Increment or decrement an identifier value, searching one or more "with" // scopes. We identify the scope as for WithPut. // // If isIncrement is true, then we increment the value, otherwise we // decrement it. If isSuffix is true, then we return the original // value, otherwise we return the modified value. public static object WithIncDec( JObject lhs, string id, bool isIncrement, bool isSuffix, params object[] withs ) { for (int i=0; i<withs.Length; i++) if (HasProperty(withs[i], id)) if (isSuffix) return Op.PreIncDecProperty(withs[i], id, isIncrement); else return Op.PostIncDecProperty(withs[i], id, isIncrement); if (isSuffix) return Op.PreIncDecProperty(lhs, id, isIncrement); else return Op.PostIncDecProperty(lhs, id, isIncrement); } // WithIncDec
} // JNumberObject constructor // Only used when creating numberPrototype. private JNumberObject(JObject prototype, double value) : base(prototype, null, "Number") { this.value = value; } // JNumberObject constructor
} // WithDelete // Compute "typeof" on an identifier value, searching one or more "with" // scopes. We identify the scope as for WithPut. public static object WithTypeof( JObject lhs, string id, params object[] withs ) { for (int i=0; i<withs.Length; i++) if (HasProperty(withs[i], id)) return TypeofProperty(withs[i], id); return TypeofProperty(lhs, id); } // WithTypeof
private JArrayObject(JObject prototype) : base(prototype, ArrayConstructorObj, "Array") {}
} // CreateTypeInstance_ // Add a property to the given object for each built-in identifier // that is defined in the global scope. public static void DefineBuiltinGlobals(JObject globals) { // HACK snewman 8/6/01: need to finish the ECMAScript spec. Make // sure that the "length" property is defined for all functions // created here. // HACK snewman 10/3/01: document the "extra" functions we define // that aren't in ECMAScript, such as writeln, GetType, and // CreateTypeInstance. globals.Put("writeln", new JFunctionObject(new JFunctionObject.JFunctionImp(writeln_), null)); globals.Put("eval", new JFunctionObject(new JFunctionObject.JFunctionImp(eval_ ), null)); globals.Put("GetType", new JFunctionObject(new JFunctionObject.JFunctionImp(GetType_), null)); globals.Put("CreateTypeInstance", new JFunctionObject(new JFunctionObject.JFunctionImp(CreateTypeInstance_), null)); // HACK snewman 10/3/01: all of these properties should be dontEnum, // dontDelete. globals.Put("NaN", Double.NaN); globals.Put("Infinity", Double.PositiveInfinity); globals.Put("undefined", JUndefinedObject.instance); RegisterBuiltins(typeof(GlobalMethods), globals); globals.Put("Object", JObject.ObjectConstructorObj); RegisterBuiltins(typeof(ObjectPrototypeMethods), JObject.ObjectPrototype); globals.Put("Boolean", JBooleanObject.BooleanConstructorObj); RegisterBuiltins(typeof(BooleanPrototypeMethods), JBooleanObject.BooleanPrototype); globals.Put("Number", JNumberObject.NumberConstructorObj); RegisterBuiltins(typeof(NumberPrototypeMethods), JNumberObject.NumberPrototype); globals.Put("Array", JArrayObject.ArrayConstructorObj); RegisterBuiltins(typeof(ArrayPrototypeMethods), JArrayObject.ArrayPrototype); globals.Put("String", JStringObject.StringConstructorObj); RegisterBuiltins(typeof(StringConstructorMethods), JStringObject.StringConstructorObj); RegisterBuiltins(typeof(StringPrototypeMethods), JStringObject.StringPrototype); JObject mathObj = new JObject(JObject.ObjectPrototype, null, "Math"); globals.Put("Math", mathObj); RegisterBuiltins(typeof(MathMethods), mathObj); // HACK snewman 10/3/01: all of these properties should be dontEnum, // dontDelete, readOnly. mathObj.Put("E", Math.E ); mathObj.Put("LN10", Math.Log(10) ); mathObj.Put("LN2", Math.Log(2) ); mathObj.Put("LOG2E", 1/Math.Log(2) ); mathObj.Put("LOG10E", 1/Math.Log(10)); mathObj.Put("PI", Math.PI ); mathObj.Put("SQRT1_2", Math.Sqrt(0.5)); mathObj.Put("SQRT2", Math.Sqrt(2) ); } // DefineBuiltinGlobals