public static mdr.DArray CreateArgumentsObject(ref mdr.CallFrame callFrame, mdr.DObject context) { var metadata = (JSFunctionMetadata)callFrame.Function.Metadata; Debug.Assert(metadata.Scope.HasArgumentsSymbol, "Invalid situation, created arguments for the wrong scope!"); mdr.DArray arguments = null; if (metadata.Scope.IsEvalFunction) { //Read from context var tmp = new mdr.DValue(); context.GetField(JSFunctionArguments.Name, ref tmp); arguments = tmp.AsDArray(); } else { arguments = CreateArgumentsObject(ref callFrame); var parameters = metadata.FunctionIR.Parameters; Debug.Assert(arguments.Length >= parameters.Count, "arguments array is not large enough to hold all arguments."); for (var i = parameters.Count - 1; i >= 0; --i) { var symbol = parameters[i].Symbol; var paramIndex = symbol.ParameterIndex; Debug.Assert(paramIndex == i, "Invalid situation!, Parameter indexes don't match!"); if (symbol.SymbolType == JSSymbol.SymbolTypes.ClosedOnLocal) { var pd = context.AddOwnPropertyDescriptorByFieldId(symbol.FieldId, mdr.PropertyDescriptor.Attributes.Accessor | mdr.PropertyDescriptor.Attributes.NotConfigurable); context.Fields[pd.Index].Set(new ArgumentAccessor(arguments, paramIndex)); } } if (metadata.Scope.HasEval) context.SetField(JSFunctionArguments.Name, arguments); } return arguments; }
private static void AddExtendedMethods(mdr.DObject obj) { #region Mozilla intrinsics obj.SetField("assertTrue", new mdr.DFunction((ref mdr.CallFrame callFrame) => { int argsLen = callFrame.PassedArgsCount; if (argsLen > 0) { var b = Operations.Convert.ToBoolean.Run(ref callFrame.Arg0); assert(b, argsLen > 1 ? callFrame.Arg1.AsString() : null); } else Trace.Fail("Not enough arguments"); })); obj.SetField("assertFalse", new mdr.DFunction((ref mdr.CallFrame callFrame) => { int argsLen = callFrame.PassedArgsCount; if (argsLen > 0) { var b = Operations.Convert.ToBoolean.Run(ref callFrame.Arg0); assert(!b, argsLen > 1 ? callFrame.Arg1.AsString() : null); } else Trace.Fail("Not enough arguments"); })); obj.SetField("assertEquals", new mdr.DFunction((ref mdr.CallFrame callFrame) => { int argsLen = callFrame.PassedArgsCount; if (argsLen > 1) { bool b = Operations.Binary.Equal.Run(ref callFrame.Arg0, ref callFrame.Arg1); assert(b, argsLen > 2 ? callFrame.Arg2.AsString() : null); } else Trace.Fail("Not enough arguments"); })); obj.SetField("assertArrayEquals", new mdr.DFunction((ref mdr.CallFrame callFrame) => { int argsLen = callFrame.PassedArgsCount; if (argsLen > 1) { var arrayA = callFrame.Arg0.AsDArray(); var arrayB = callFrame.Arg1.AsDArray(); bool areEqual = true; if (arrayA != null && arrayB != null && arrayA.Length == arrayB.Length) { for (int i = 0; i < arrayA.Length; i++) if (Operations.Binary.Equal.Run(ref arrayA.Elements[i], ref arrayB.Elements[i])) { areEqual = false; break; } } else if (arrayA != arrayB) areEqual = false; assert(areEqual, argsLen > 2 ? callFrame.Arg2.AsString() : null); } else Trace.Fail("Not enough arguments"); })); #endregion // FIXME: The below causes an infinite recursion in CodeSourceGenerator. Commenting for now. - SF //SetField("global", this); //to enable access to global scope directly! obj.SetField("print", new mdr.DFunction((ref mdr.CallFrame callFrame) => { var l = callFrame.PassedArgsCount; for (var i = 0; i < l; ++i) { var arg = callFrame.Arg(i); string s = ToString(ref arg); Console.Write("{0}{1}", s, (i < l - 1) ? " " : ""); } Console.WriteLine(); })); obj.SetField("load", new mdr.DFunction((ref mdr.CallFrame callFrame) => { var l = callFrame.PassedArgsCount; if (l < 1) throw new Exception("load must have an argument"); var filename = callFrame.Arg0.AsString(); JSRuntime.Instance.RunScriptFile(filename); })); #region __mcjs__ object { var mcjs = new mdr.DObject(mdr.Runtime.Instance.EmptyPropertyMapMetadata.Root); obj.SetField("__mcjs__", mcjs); mcjs.SetField("SetSwitch", new mdr.DFunction((ref mdr.CallFrame callFrame) => { var switchName = callFrame.Arg0.AsString(); var switchValue = Operations.Convert.ToBoolean.Run(ref callFrame.Arg1); var prop = typeof(JSRuntimeConfiguration).GetProperty(switchName, CodeGen.Types.ClrSys.Boolean); if (prop != null) prop.GetSetMethod().Invoke(JSRuntime.Instance.Configuration, new object[] { switchValue }); else Debug.WriteLine("JSRuntime.Instance.Configuration does not contain the switch '{0}'", switchName); })); mcjs.SetField("PrintDump", new mdr.DFunction((ref mdr.CallFrame callFrame) => { var l = callFrame.PassedArgsCount; if (l != 1) throw new Exception("PrintDump must have one argument"); Debug.WriteLine("##JS: {0}", callFrame.Arg0.AsString()); #if DEBUG //Check for android log directory if (printOutFile == null) { printOutFile = System.IO.File.CreateText(System.IO.Path.Combine(JSRuntime.Instance.Configuration.OutputDir, "mcprint" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString() + ".out")); } printOutFile.Write("{0}", callFrame.Arg0.AsString()); printOutFile.Flush(); //Debug.WriteLine("MCPRINTVAR: {0}={1}", callFrame.Arg1.ToString(), s); #endif })); } #endregion }
internal static void Init(mdr.DObject obj) { obj.SetField("global", obj); //obj.SetField("null", mdr.Runtime.Instance.DefaultDNull); obj.DefineOwnProperty("undefined", mdr.Runtime.Instance.DefaultDUndefined, mdr.PropertyDescriptor.Attributes.Data | mdr.PropertyDescriptor.Attributes.NotWritable | mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.NotConfigurable); obj.DefineOwnProperty("NaN", double.NaN, mdr.PropertyDescriptor.Attributes.Data | mdr.PropertyDescriptor.Attributes.NotWritable | mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.NotConfigurable); obj.DefineOwnProperty("Infinity", double.PositiveInfinity, mdr.PropertyDescriptor.Attributes.Data | mdr.PropertyDescriptor.Attributes.NotWritable | mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.NotConfigurable); obj.SetField("Object", new JSObject()); obj.SetField("Function", new JSFunction()); obj.SetField("Array", new JSArray()); obj.SetField("ArrayBuffer", new JSArrayBuffer()); obj.SetField("Int8Array", new JSInt8Array()); obj.SetField("Uint8Array", new JSUint8Array()); obj.SetField("Int16Array", new JSInt16Array()); obj.SetField("Uint16Array", new JSUint16Array()); obj.SetField("Int32Array", new JSInt32Array()); obj.SetField("Uint32Array", new JSUint32Array()); obj.SetField("Float32Array", new JSFloat32Array()); obj.SetField("Float64Array", new JSFloat64Array()); obj.SetField("Math", new JSMath()); obj.SetField("String", new JSString()); obj.SetField("Number", new JSNumber()); obj.SetField("Date", new JSDate()); obj.SetField("Boolean", new JSBoolean()); obj.SetField("Error", new JSError()); obj.SetField("RegExp", new JSRegExp()); obj.SetField("eval", BuiltinEval); AddStandardMethods(obj); AddExtendedMethods(obj); }
// TODO: These are currently unused; can we remove them? /*private static char[] reservedEncoded = new char[] { ';', ',', '/', '?', ':', '@', '&', '=', '+', '$', '#' }; private static char[] reservedEncodedComponent = new char[] { '-', '_', '.', '!', '~', '*', '\'', '(', ')', '[', ']' };*/ private static void AddStandardMethods(mdr.DObject obj) { obj.SetField("ToNumber", new mdr.DFunction((ref mdr.CallFrame callFrame) => { if (callFrame.PassedArgsCount > 0) callFrame.Return.Set(Operations.Convert.ToDouble.Run(ref callFrame.Arg0)); else callFrame.Return.Set(double.NaN); })); obj.SetField("isNaN", new mdr.DFunction((ref mdr.CallFrame callFrame) => { if (callFrame.PassedArgsCount > 0) callFrame.Return.Set(double.IsNaN(Operations.Convert.ToDouble.Run(ref callFrame.Arg0))); else callFrame.Return.Set(false); })); obj.SetField("isFinite", new mdr.DFunction((ref mdr.CallFrame callFrame) => { if (callFrame.PassedArgsCount > 0) { double arg = Operations.Convert.ToDouble.Run(ref callFrame.Arg0); callFrame.Return.Set(double.IsNaN(arg) || !double.IsInfinity(arg)); } else callFrame.Return.Set(false); })); obj.SetField("assert", new mdr.DFunction((ref mdr.CallFrame callFrame) => { for (int i = 0; i < callFrame.PassedArgsCount; ++i) { var b = Operations.Convert.ToBoolean.Run(ref callFrame.Arg0); if (!b) throw new Exception("Error in script"); } })); //ECMA-262: 15.1.2.2 obj.SetField("parseInt", new mdr.DFunction((ref mdr.CallFrame callFrame) => { if (callFrame.PassedArgsCount == 1 && mdr.ValueTypesHelper.IsNumber(callFrame.Arg0.ValueType)) callFrame.Return.Set(Operations.Convert.ToInt32.Run(ref callFrame.Arg0)); else { string stringArg = Operations.Convert.ToString.Run(ref callFrame.Arg0).TrimStart(); int sign = 1; if (stringArg[0] == '-' || stringArg[0] == '+') { if (stringArg[0] == '-') sign = -1; stringArg = stringArg.Remove(0, 1); } bool stripPrefix = true; int radix = 10; if (callFrame.PassedArgsCount > 1) { radix = Operations.Convert.ToInt32.Run(ref callFrame.Arg1); if (radix != 0) { if (radix < 2 || radix > 36) { callFrame.Return.Set(double.NaN); return; } if (radix != 16) stripPrefix = false; } else radix = 10; } if (stripPrefix && (stringArg.StartsWith("0x") || stringArg.StartsWith("0X"))) { stringArg = stringArg.Remove(0, 2); radix = 16; } callFrame.Return.Set(MathInt(stringArg, radix) * sign); } })); //ECMA-262: 15.1.2.3 obj.SetField("parseFloat", new mdr.DFunction((ref mdr.CallFrame callFrame) => { string stringArg = (Operations.Convert.ToString.Run(ref callFrame.Arg0)).TrimStart(); char[] charArg = stringArg.TrimEnd().ToCharArray(); int len = charArg.Length; if (len == 0) { callFrame.Return.Set(double.NaN); return; } if (len == 1) { if (char.IsDigit(charArg[0])) { callFrame.Return.Set((double)(charArg[0] - '0')); return; } } int i = 0; if (charArg[0] == '-' || charArg[0] == '+') i = 1; bool punctation = false; for (; i < charArg.Length; ++i) { if (!char.IsLetterOrDigit(charArg[i]) && charArg[i] != '.') break; if (charArg[i] == '-') break; if (punctation && charArg[i] == '.') break; if (charArg[i] == '.') punctation = true; } stringArg = stringArg.Substring(0, i); double value = 0; if (Double.TryParse(stringArg, out value)) { callFrame.Return.Set(value); return; } callFrame.Return.Set(double.NaN); })); //ECMA-262: 15.1.3.1 obj.SetField("decodeURI", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSGlobalObject.decodeURI"); string uri = callFrame.Arg0.AsString(); callFrame.Return.Set(URIHandling.Decode(uri, URIHandling.uriReserved + "#")); })); //ECMA-262: 15.1.3.2 obj.SetField("decodeURIComponent", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSGlobalObject.decodeURIComponent"); if (callFrame.PassedArgsCount < 1 || callFrame.Arg0.ValueType == mdr.ValueTypes.Undefined) { callFrame.Return.Set(""); return; } callFrame.Return.Set(URIHandling.Decode(callFrame.Arg0.AsString(), string.Empty)); })); //ECMA-262: 15.1.3.3 obj.SetField("encodeURI", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSGlobalObject.encodeURI"); string uri = callFrame.Arg0.AsString(); callFrame.Return.Set(URIHandling.Encode(uri, URIHandling.UriUnescaped + URIHandling.uriReserved + "#")); })); //ECMA-262: 15.1.3.4 obj.SetField("encodeURIComponent", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSGlobalObject.encodeURIComponent"); if (callFrame.PassedArgsCount < 1 || callFrame.Arg0.ValueType == mdr.ValueTypes.Undefined) { callFrame.Return.Set(""); return; } callFrame.Return.Set(URIHandling.Encode(callFrame.Arg0.AsString(), URIHandling.UriUnescaped)); })); obj.SetField("escape", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSGlobalObject.escape"); if (callFrame.PassedArgsCount == 1) { string stringArg = callFrame.Arg0.AsString(); if (stringArg == null) { callFrame.Return.Set(""); } else { string escArg = URIHandling.Escape(stringArg); callFrame.Return.Set(escArg); } } else { callFrame.Return.Set(""); } })); obj.SetField("unescape", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSGlobalObject.unescape"); string stringArg = callFrame.Arg0.AsString(); string unescArg = URIHandling.Unescape(stringArg); callFrame.Return.Set(unescArg); })); }