|
@@ -2,277 +2,134 @@
|
|
using System.Collections.Generic;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Diagnostics;
|
|
using System.Diagnostics.Contracts;
|
|
using System.Diagnostics.Contracts;
|
|
-using System.Dynamic;
|
|
|
|
-using System.Runtime.CompilerServices;
|
|
|
|
using System.Threading;
|
|
using System.Threading;
|
|
using Jint.Native.Array;
|
|
using Jint.Native.Array;
|
|
-using Jint.Native.Boolean;
|
|
|
|
using Jint.Native.Date;
|
|
using Jint.Native.Date;
|
|
-using Jint.Native.Function;
|
|
|
|
-using Jint.Native.Number;
|
|
|
|
using Jint.Native.Object;
|
|
using Jint.Native.Object;
|
|
using Jint.Native.RegExp;
|
|
using Jint.Native.RegExp;
|
|
-using Jint.Native.String;
|
|
|
|
using Jint.Runtime;
|
|
using Jint.Runtime;
|
|
using Jint.Runtime.Interop;
|
|
using Jint.Runtime.Interop;
|
|
|
|
|
|
namespace Jint.Native
|
|
namespace Jint.Native
|
|
{
|
|
{
|
|
[DebuggerTypeProxy(typeof(JsValueDebugView))]
|
|
[DebuggerTypeProxy(typeof(JsValueDebugView))]
|
|
- public class JsValue : IEquatable<JsValue>
|
|
|
|
|
|
+ public abstract class JsValue : IEquatable<JsValue>
|
|
{
|
|
{
|
|
- // how many decimals to check when determining if double is actually an int
|
|
|
|
- private const double DoubleIsIntegerTolerance = double.Epsilon * 100;
|
|
|
|
-
|
|
|
|
- private static readonly long NegativeZeroBits = BitConverter.DoubleToInt64Bits(-0.0);
|
|
|
|
-
|
|
|
|
- // we can cache most common values, doubles are used in indexing too at times so we also cache
|
|
|
|
- // integer values converted to doubles
|
|
|
|
- private const int NumbersMax = 1024 * 10;
|
|
|
|
- private static readonly JsValue[] _doubleToJsValue = new JsValue[NumbersMax];
|
|
|
|
- private static readonly JsValue[] _intToJsValue = new JsValue[NumbersMax];
|
|
|
|
-
|
|
|
|
- private const int AsciiMax = 126;
|
|
|
|
- private static readonly JsValue[] _charToJsValue = new JsValue[AsciiMax + 1];
|
|
|
|
- private static readonly JsValue[] _charToStringJsValue = new JsValue[AsciiMax + 1];
|
|
|
|
-
|
|
|
|
- private static readonly JsValue EmptyString = new JsValue("");
|
|
|
|
- private static readonly JsValue NullString = new JsValue("null");
|
|
|
|
-
|
|
|
|
- public static readonly JsValue Undefined = new JsValue(Types.Undefined);
|
|
|
|
- public static readonly JsValue Null = new JsValue(Types.Null);
|
|
|
|
- public static readonly JsValue False = new JsValue(false);
|
|
|
|
- public static readonly JsValue True = new JsValue(true);
|
|
|
|
-
|
|
|
|
- private static readonly JsValue DoubleNaN = new JsValue(double.NaN);
|
|
|
|
- private static readonly JsValue DoubleNegativeOne = new JsValue((double) -1);
|
|
|
|
- private static readonly JsValue DoublePositiveInfinity= new JsValue(double.PositiveInfinity);
|
|
|
|
- private static readonly JsValue DoubleNegativeInfinity = new JsValue(double.NegativeInfinity);
|
|
|
|
- private static readonly JsValue IntegerNegativeOne = new JsValue(-1);
|
|
|
|
-
|
|
|
|
- private readonly double _double;
|
|
|
|
- private readonly object _object;
|
|
|
|
- protected Types _type;
|
|
|
|
-
|
|
|
|
- static JsValue()
|
|
|
|
- {
|
|
|
|
- for (int i = 0; i < NumbersMax; i++)
|
|
|
|
- {
|
|
|
|
- _intToJsValue[i] = new JsValue(i);
|
|
|
|
- _doubleToJsValue[i] = new JsValue((double) i);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- for (int i = 0; i <= AsciiMax; i++)
|
|
|
|
- {
|
|
|
|
- _charToJsValue[i] = new JsValue((char) i);
|
|
|
|
- _charToStringJsValue[i] = new JsValue(((char) i).ToString());
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public JsValue(bool value)
|
|
|
|
- {
|
|
|
|
- _double = value ? 1.0 : 0.0;
|
|
|
|
- _object = null;
|
|
|
|
- _type = Types.Boolean;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public JsValue(double value)
|
|
|
|
- {
|
|
|
|
- _object = null;
|
|
|
|
- _type = Types.Number;
|
|
|
|
-
|
|
|
|
- _double = value;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public JsValue(int value)
|
|
|
|
- {
|
|
|
|
- _object = null;
|
|
|
|
- _type = Types.Number;
|
|
|
|
-
|
|
|
|
- _double = value;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public JsValue(uint value)
|
|
|
|
- {
|
|
|
|
- _object = null;
|
|
|
|
- _type = Types.Number;
|
|
|
|
-
|
|
|
|
- _double = value;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public JsValue(char value)
|
|
|
|
- {
|
|
|
|
- _double = double.NaN;
|
|
|
|
- _object = value;
|
|
|
|
- _type = Types.String;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public JsValue(string value)
|
|
|
|
- {
|
|
|
|
- _double = double.NaN;
|
|
|
|
- _object = value;
|
|
|
|
- _type = Types.String;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public JsValue(ObjectInstance value)
|
|
|
|
- {
|
|
|
|
- _double = double.NaN;
|
|
|
|
- _type = Types.Object;
|
|
|
|
-
|
|
|
|
- _object = value;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public JsValue(Completion value)
|
|
|
|
- {
|
|
|
|
- _double = double.NaN;
|
|
|
|
- _type = Types.Completion;
|
|
|
|
-
|
|
|
|
- _object = value;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private JsValue(Types type)
|
|
|
|
- {
|
|
|
|
- _double = double.NaN;
|
|
|
|
- _object = null;
|
|
|
|
- _type = type;
|
|
|
|
- }
|
|
|
|
|
|
+ public static readonly JsValue Undefined = new JsUndefined();
|
|
|
|
+ public static readonly JsValue Null = new JsNull();
|
|
|
|
|
|
[Pure]
|
|
[Pure]
|
|
public bool IsPrimitive()
|
|
public bool IsPrimitive()
|
|
{
|
|
{
|
|
- return _type != Types.Object && _type != Types.None;
|
|
|
|
|
|
+ return Type != Types.Object && Type != Types.None;
|
|
}
|
|
}
|
|
|
|
|
|
[Pure]
|
|
[Pure]
|
|
public bool IsUndefined()
|
|
public bool IsUndefined()
|
|
{
|
|
{
|
|
- return _type == Types.Undefined;
|
|
|
|
|
|
+ return Type == Types.Undefined;
|
|
}
|
|
}
|
|
|
|
|
|
[Pure]
|
|
[Pure]
|
|
- public bool IsArray()
|
|
|
|
|
|
+ public virtual bool IsArray()
|
|
{
|
|
{
|
|
- return _type == Types.Object && _object is ArrayInstance;
|
|
|
|
|
|
+ return false;
|
|
}
|
|
}
|
|
|
|
|
|
[Pure]
|
|
[Pure]
|
|
- public bool IsDate()
|
|
|
|
|
|
+ public virtual bool IsDate()
|
|
{
|
|
{
|
|
- return _type == Types.Object && _object is DateInstance;
|
|
|
|
|
|
+ return false;
|
|
}
|
|
}
|
|
|
|
|
|
[Pure]
|
|
[Pure]
|
|
- public bool IsRegExp()
|
|
|
|
|
|
+ public virtual bool IsRegExp()
|
|
{
|
|
{
|
|
- return _type == Types.Object && _object is RegExpInstance;
|
|
|
|
|
|
+ return false;
|
|
}
|
|
}
|
|
|
|
|
|
[Pure]
|
|
[Pure]
|
|
public bool IsObject()
|
|
public bool IsObject()
|
|
{
|
|
{
|
|
- return _type == Types.Object;
|
|
|
|
|
|
+ return Type == Types.Object;
|
|
}
|
|
}
|
|
|
|
|
|
[Pure]
|
|
[Pure]
|
|
public bool IsString()
|
|
public bool IsString()
|
|
{
|
|
{
|
|
- return _type == Types.String;
|
|
|
|
|
|
+ return Type == Types.String;
|
|
}
|
|
}
|
|
|
|
|
|
[Pure]
|
|
[Pure]
|
|
public bool IsNumber()
|
|
public bool IsNumber()
|
|
{
|
|
{
|
|
- return _type == Types.Number;
|
|
|
|
|
|
+ return Type == Types.Number;
|
|
}
|
|
}
|
|
|
|
|
|
[Pure]
|
|
[Pure]
|
|
public bool IsBoolean()
|
|
public bool IsBoolean()
|
|
{
|
|
{
|
|
- return _type == Types.Boolean;
|
|
|
|
|
|
+ return Type == Types.Boolean;
|
|
}
|
|
}
|
|
|
|
|
|
[Pure]
|
|
[Pure]
|
|
public bool IsNull()
|
|
public bool IsNull()
|
|
{
|
|
{
|
|
- return _type == Types.Null;
|
|
|
|
|
|
+ return Type == Types.Null;
|
|
}
|
|
}
|
|
|
|
|
|
[Pure]
|
|
[Pure]
|
|
public bool IsCompletion()
|
|
public bool IsCompletion()
|
|
{
|
|
{
|
|
- return _type == Types.Completion;
|
|
|
|
|
|
+ return Type == Types.Completion;
|
|
}
|
|
}
|
|
|
|
|
|
[Pure]
|
|
[Pure]
|
|
public bool IsSymbol()
|
|
public bool IsSymbol()
|
|
{
|
|
{
|
|
- return _type == Types.Symbol;
|
|
|
|
|
|
+ return Type == Types.Symbol;
|
|
}
|
|
}
|
|
|
|
|
|
[Pure]
|
|
[Pure]
|
|
- public ObjectInstance AsObject()
|
|
|
|
|
|
+ public virtual ObjectInstance AsObject()
|
|
{
|
|
{
|
|
- if (_type != Types.Object)
|
|
|
|
- {
|
|
|
|
- throw new ArgumentException("The value is not an object");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return _object as ObjectInstance;
|
|
|
|
|
|
+ throw new ArgumentException("The value is not an object");
|
|
}
|
|
}
|
|
|
|
|
|
[Pure]
|
|
[Pure]
|
|
- public TInstance AsInstance<TInstance>() where TInstance : class
|
|
|
|
|
|
+ public virtual TInstance AsInstance<TInstance>() where TInstance : class
|
|
{
|
|
{
|
|
- if (_type != Types.Object)
|
|
|
|
- {
|
|
|
|
- throw new ArgumentException("The value is not an object");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return _object as TInstance;
|
|
|
|
|
|
+ throw new ArgumentException("The value is not an object");
|
|
}
|
|
}
|
|
|
|
|
|
[Pure]
|
|
[Pure]
|
|
- public ArrayInstance AsArray()
|
|
|
|
|
|
+ public virtual ArrayInstance AsArray()
|
|
{
|
|
{
|
|
- if (!IsArray())
|
|
|
|
- {
|
|
|
|
- throw new ArgumentException("The value is not an array");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return _object as ArrayInstance;
|
|
|
|
|
|
+ throw new ArgumentException("The value is not an array");
|
|
}
|
|
}
|
|
|
|
|
|
[Pure]
|
|
[Pure]
|
|
- public DateInstance AsDate()
|
|
|
|
|
|
+ public virtual DateInstance AsDate()
|
|
{
|
|
{
|
|
- if (!IsDate())
|
|
|
|
- {
|
|
|
|
- throw new ArgumentException("The value is not a date");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return _object as DateInstance;
|
|
|
|
|
|
+ throw new ArgumentException("The value is not a date");
|
|
}
|
|
}
|
|
|
|
|
|
[Pure]
|
|
[Pure]
|
|
- public RegExpInstance AsRegExp()
|
|
|
|
|
|
+ public virtual RegExpInstance AsRegExp()
|
|
{
|
|
{
|
|
- if (!IsRegExp())
|
|
|
|
- {
|
|
|
|
- throw new ArgumentException("The value is not a date");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return _object as RegExpInstance;
|
|
|
|
|
|
+ throw new ArgumentException("The value is not a date");
|
|
}
|
|
}
|
|
|
|
|
|
[Pure]
|
|
[Pure]
|
|
- public Completion AsCompletion()
|
|
|
|
|
|
+ public virtual Completion AsCompletion()
|
|
{
|
|
{
|
|
- if (_type != Types.Completion)
|
|
|
|
|
|
+ if (Type != Types.Completion)
|
|
{
|
|
{
|
|
throw new ArgumentException("The value is not a completion record");
|
|
throw new ArgumentException("The value is not a completion record");
|
|
}
|
|
}
|
|
|
|
|
|
- return (Completion)_object;
|
|
|
|
|
|
+ // TODO not implemented
|
|
|
|
+ return null;
|
|
}
|
|
}
|
|
|
|
|
|
[Pure]
|
|
[Pure]
|
|
@@ -293,177 +150,41 @@ namespace Jint.Native
|
|
return null;
|
|
return null;
|
|
}
|
|
}
|
|
|
|
|
|
- public bool Is<T>()
|
|
|
|
|
|
+ public virtual bool Is<T>()
|
|
{
|
|
{
|
|
- return _type == Types.Object && _object is T;
|
|
|
|
|
|
+ return false;
|
|
}
|
|
}
|
|
|
|
|
|
- public T As<T>() where T : ObjectInstance
|
|
|
|
|
|
+ public virtual T As<T>() where T : ObjectInstance
|
|
{
|
|
{
|
|
- return _object as T;
|
|
|
|
|
|
+ return null;
|
|
}
|
|
}
|
|
|
|
|
|
[Pure]
|
|
[Pure]
|
|
- public bool AsBoolean()
|
|
|
|
|
|
+ public virtual bool AsBoolean()
|
|
{
|
|
{
|
|
- if (_type != Types.Boolean)
|
|
|
|
- {
|
|
|
|
- throw new ArgumentException("The value is not a boolean");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return _double != 0;
|
|
|
|
|
|
+ throw new ArgumentException("The value is not a boolean");
|
|
}
|
|
}
|
|
|
|
|
|
[Pure]
|
|
[Pure]
|
|
- public string AsString()
|
|
|
|
|
|
+ public virtual string AsString()
|
|
{
|
|
{
|
|
- if (_type != Types.String)
|
|
|
|
- {
|
|
|
|
- throw new ArgumentException("The value is not a string");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (_object == null)
|
|
|
|
- {
|
|
|
|
- throw new ArgumentException("The value is not defined");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return (string)_object;
|
|
|
|
|
|
+ throw new ArgumentException("The value is not a string");
|
|
}
|
|
}
|
|
|
|
|
|
[Pure]
|
|
[Pure]
|
|
- public string AsSymbol()
|
|
|
|
|
|
+ public virtual string AsSymbol()
|
|
{
|
|
{
|
|
- if (_type != Types.Symbol)
|
|
|
|
- {
|
|
|
|
- throw new ArgumentException("The value is not a symbol");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (_object == null)
|
|
|
|
- {
|
|
|
|
- throw new ArgumentException("The value is not defined");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return (string)_object;
|
|
|
|
|
|
+ throw new ArgumentException("The value is not a symbol");
|
|
}
|
|
}
|
|
|
|
|
|
[Pure]
|
|
[Pure]
|
|
- public double AsNumber()
|
|
|
|
- {
|
|
|
|
- if (_type != Types.Number)
|
|
|
|
- {
|
|
|
|
- throw new ArgumentException("The value is not a number");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return _double;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
- public bool Equals(JsValue other)
|
|
|
|
- {
|
|
|
|
- if (other == null)
|
|
|
|
- {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if(ReferenceEquals(this, other))
|
|
|
|
- {
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (_type != other._type)
|
|
|
|
- {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- switch (_type)
|
|
|
|
- {
|
|
|
|
- case Types.None:
|
|
|
|
- return false;
|
|
|
|
- case Types.Undefined:
|
|
|
|
- return true;
|
|
|
|
- case Types.Null:
|
|
|
|
- return true;
|
|
|
|
- case Types.Boolean:
|
|
|
|
- case Types.Number:
|
|
|
|
- return _double == other._double;
|
|
|
|
- case Types.String:
|
|
|
|
- case Types.Object:
|
|
|
|
- return _object == other._object;
|
|
|
|
- default:
|
|
|
|
- throw new ArgumentOutOfRangeException();
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public Types Type => _type;
|
|
|
|
-
|
|
|
|
- internal static JsValue FromDouble(double value)
|
|
|
|
- {
|
|
|
|
- // we can cache positive double zero, but not negative, -0 == 0 in C# but in JS it's a different story
|
|
|
|
- if ((value == 0 && BitConverter.DoubleToInt64Bits(value) != NegativeZeroBits || value >= 1)
|
|
|
|
- && value < _doubleToJsValue.Length
|
|
|
|
- && System.Math.Abs(value % 1) <= DoubleIsIntegerTolerance)
|
|
|
|
- {
|
|
|
|
- return _doubleToJsValue[(int) value];
|
|
|
|
- }
|
|
|
|
- if (value == -1)
|
|
|
|
- {
|
|
|
|
- return DoubleNegativeOne;
|
|
|
|
- }
|
|
|
|
- if (value == double.NegativeInfinity)
|
|
|
|
- {
|
|
|
|
- return DoubleNegativeInfinity;
|
|
|
|
- }
|
|
|
|
- if (value == double.PositiveInfinity)
|
|
|
|
- {
|
|
|
|
- return DoublePositiveInfinity;
|
|
|
|
- }
|
|
|
|
- if (double.IsNaN(value))
|
|
|
|
- {
|
|
|
|
- return DoubleNaN;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return new JsValue(value);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- internal static JsValue FromInt(int value)
|
|
|
|
- {
|
|
|
|
- if (value >= 0 && value < _intToJsValue.Length)
|
|
|
|
- {
|
|
|
|
- return _intToJsValue[value];
|
|
|
|
- }
|
|
|
|
- if (value == -1)
|
|
|
|
- {
|
|
|
|
- return IntegerNegativeOne;
|
|
|
|
- }
|
|
|
|
- return new JsValue(value);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- internal static JsValue FromInt(uint value)
|
|
|
|
|
|
+ public virtual double AsNumber()
|
|
{
|
|
{
|
|
- if (value >= 0 && value < _intToJsValue.Length)
|
|
|
|
- {
|
|
|
|
- return _intToJsValue[value];
|
|
|
|
- }
|
|
|
|
- return new JsValue(value);
|
|
|
|
|
|
+ throw new ArgumentException("The value is not a number");
|
|
}
|
|
}
|
|
|
|
|
|
- internal static JsValue FromInt(ulong value)
|
|
|
|
- {
|
|
|
|
- if (value >= 0 && value < (ulong) _intToJsValue.Length)
|
|
|
|
- {
|
|
|
|
- return _intToJsValue[value];
|
|
|
|
- }
|
|
|
|
- return new JsValue(value);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- internal static JsValue FromChar(char value)
|
|
|
|
- {
|
|
|
|
- if (value >= 0 && value <= AsciiMax)
|
|
|
|
- {
|
|
|
|
- return _charToJsValue[value];
|
|
|
|
- }
|
|
|
|
- return new JsValue(value);
|
|
|
|
- }
|
|
|
|
|
|
+ public abstract Types Type { get; }
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Creates a valid <see cref="JsValue"/> instance from any <see cref="Object"/> instance
|
|
/// Creates a valid <see cref="JsValue"/> instance from any <see cref="Object"/> instance
|
|
@@ -478,6 +199,11 @@ namespace Jint.Native
|
|
return Null;
|
|
return Null;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (value is JsValue jsValue)
|
|
|
|
+ {
|
|
|
|
+ return jsValue;
|
|
|
|
+ }
|
|
|
|
+
|
|
foreach (var converter in engine.Options._ObjectConverters)
|
|
foreach (var converter in engine.Options._ObjectConverters)
|
|
{
|
|
{
|
|
if (converter.TryConvert(value, out var result))
|
|
if (converter.TryConvert(value, out var result))
|
|
@@ -495,23 +221,11 @@ namespace Jint.Native
|
|
return typeMapper(engine, value);
|
|
return typeMapper(engine, value);
|
|
}
|
|
}
|
|
|
|
|
|
- // if an ObjectInstance is passed directly, use it as is
|
|
|
|
- if (value is ObjectInstance instance)
|
|
|
|
- {
|
|
|
|
- // Learn conversion.
|
|
|
|
- // Learn conversion, racy, worst case we'll try again later
|
|
|
|
- Interlocked.CompareExchange(ref Engine.TypeMappers, new Dictionary<Type, Func<Engine, object, JsValue>>(typeMappers)
|
|
|
|
- {
|
|
|
|
- [valueType] = (Engine e, object v) => ((ObjectInstance)v).JsValue
|
|
|
|
- }, typeMappers);
|
|
|
|
- return instance.JsValue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
var type = value as Type;
|
|
var type = value as Type;
|
|
- if(type != null)
|
|
|
|
|
|
+ if (type != null)
|
|
{
|
|
{
|
|
var typeReference = TypeReference.CreateTypeReference(engine, type);
|
|
var typeReference = TypeReference.CreateTypeReference(engine, type);
|
|
- return typeReference.JsValue;
|
|
|
|
|
|
+ return typeReference;
|
|
}
|
|
}
|
|
|
|
|
|
if (value is System.Array a)
|
|
if (value is System.Array a)
|
|
@@ -545,7 +259,7 @@ namespace Jint.Native
|
|
|
|
|
|
if (value.GetType().IsEnum())
|
|
if (value.GetType().IsEnum())
|
|
{
|
|
{
|
|
- return FromInt((int) value);
|
|
|
|
|
|
+ return JsNumber.Create((int) value);
|
|
}
|
|
}
|
|
|
|
|
|
// if no known type could be guessed, wrap it as an ObjectInstance
|
|
// if no known type could be guessed, wrap it as an ObjectInstance
|
|
@@ -556,127 +270,7 @@ namespace Jint.Native
|
|
/// Converts a <see cref="JsValue"/> to its underlying CLR value.
|
|
/// Converts a <see cref="JsValue"/> to its underlying CLR value.
|
|
/// </summary>
|
|
/// </summary>
|
|
/// <returns>The underlying CLR value of the <see cref="JsValue"/> instance.</returns>
|
|
/// <returns>The underlying CLR value of the <see cref="JsValue"/> instance.</returns>
|
|
- public object ToObject()
|
|
|
|
- {
|
|
|
|
- switch (_type)
|
|
|
|
- {
|
|
|
|
- case Types.None:
|
|
|
|
- case Types.Undefined:
|
|
|
|
- case Types.Null:
|
|
|
|
- return null;
|
|
|
|
- case Types.String:
|
|
|
|
- return _object;
|
|
|
|
- case Types.Boolean:
|
|
|
|
- return _double != 0;
|
|
|
|
- case Types.Number:
|
|
|
|
- return _double;
|
|
|
|
- case Types.Object:
|
|
|
|
- if (_object is IObjectWrapper wrapper)
|
|
|
|
- {
|
|
|
|
- return wrapper.Target;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- switch ((_object as ObjectInstance).Class)
|
|
|
|
- {
|
|
|
|
- case "Array":
|
|
|
|
- if (_object is ArrayInstance arrayInstance)
|
|
|
|
- {
|
|
|
|
- var len = TypeConverter.ToInt32(arrayInstance.Get("length"));
|
|
|
|
- var result = new object[len];
|
|
|
|
- for (var k = 0; k < len; k++)
|
|
|
|
- {
|
|
|
|
- var pk = TypeConverter.ToString(k);
|
|
|
|
- var kpresent = arrayInstance.HasProperty(pk);
|
|
|
|
- if (kpresent)
|
|
|
|
- {
|
|
|
|
- var kvalue = arrayInstance.Get(pk);
|
|
|
|
- result[k] = kvalue.ToObject();
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- result[k] = null;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return result;
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case "String":
|
|
|
|
- if (_object is StringInstance stringInstance)
|
|
|
|
- {
|
|
|
|
- return stringInstance.PrimitiveValue.AsString();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case "Date":
|
|
|
|
- if (_object is DateInstance dateInstance)
|
|
|
|
- {
|
|
|
|
- return dateInstance.ToDateTime();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case "Boolean":
|
|
|
|
- if (_object is BooleanInstance booleanInstance)
|
|
|
|
- {
|
|
|
|
- return booleanInstance.PrimitiveValue.AsBoolean();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case "Function":
|
|
|
|
- if (_object is FunctionInstance function)
|
|
|
|
- {
|
|
|
|
- return (Func<JsValue, JsValue[], JsValue>)function.Call;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case "Number":
|
|
|
|
- if (_object is NumberInstance numberInstance)
|
|
|
|
- {
|
|
|
|
- return numberInstance.NumberData.AsNumber();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case "RegExp":
|
|
|
|
- if (_object is RegExpInstance regeExpInstance)
|
|
|
|
- {
|
|
|
|
- return regeExpInstance.Value;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case "Arguments":
|
|
|
|
- case "Object":
|
|
|
|
-#if __IOS__
|
|
|
|
- IDictionary<string, object> o = new Dictionary<string, object>();
|
|
|
|
-#else
|
|
|
|
- IDictionary<string, object> o = new ExpandoObject();
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
- var objectInstance = (ObjectInstance) _object;
|
|
|
|
- foreach (var p in objectInstance.GetOwnProperties())
|
|
|
|
- {
|
|
|
|
- if (!p.Value.Enumerable.HasValue || p.Value.Enumerable.Value == false)
|
|
|
|
- {
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- o.Add(p.Key, objectInstance.Get(p.Key).ToObject());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return o;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- return _object;
|
|
|
|
- default:
|
|
|
|
- throw new ArgumentOutOfRangeException();
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ public abstract object ToObject();
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Invoke the current value as function.
|
|
/// Invoke the current value as function.
|
|
@@ -726,24 +320,7 @@ namespace Jint.Native
|
|
|
|
|
|
public override string ToString()
|
|
public override string ToString()
|
|
{
|
|
{
|
|
- switch (Type)
|
|
|
|
- {
|
|
|
|
- case Types.None:
|
|
|
|
- return "None";
|
|
|
|
- case Types.Undefined:
|
|
|
|
- return "undefined";
|
|
|
|
- case Types.Null:
|
|
|
|
- return "null";
|
|
|
|
- case Types.Boolean:
|
|
|
|
- return _double != 0 ? bool.TrueString : bool.FalseString;
|
|
|
|
- case Types.Number:
|
|
|
|
- return _double.ToString();
|
|
|
|
- case Types.String:
|
|
|
|
- case Types.Object:
|
|
|
|
- return _object.ToString();
|
|
|
|
- default:
|
|
|
|
- return string.Empty;
|
|
|
|
- }
|
|
|
|
|
|
+ return "None";
|
|
}
|
|
}
|
|
|
|
|
|
public static bool operator ==(JsValue a, JsValue b)
|
|
public static bool operator ==(JsValue a, JsValue b)
|
|
@@ -788,66 +365,62 @@ namespace Jint.Native
|
|
|
|
|
|
static public implicit operator JsValue(char value)
|
|
static public implicit operator JsValue(char value)
|
|
{
|
|
{
|
|
- return FromChar(value);
|
|
|
|
|
|
+ return JsString.Create(value);
|
|
}
|
|
}
|
|
|
|
|
|
static public implicit operator JsValue(int value)
|
|
static public implicit operator JsValue(int value)
|
|
{
|
|
{
|
|
- return FromInt(value);
|
|
|
|
|
|
+ return JsNumber.Create(value);
|
|
}
|
|
}
|
|
|
|
|
|
static public implicit operator JsValue(uint value)
|
|
static public implicit operator JsValue(uint value)
|
|
{
|
|
{
|
|
- return FromInt(value);
|
|
|
|
|
|
+ return JsNumber.Create(value);
|
|
}
|
|
}
|
|
|
|
|
|
static public implicit operator JsValue(double value)
|
|
static public implicit operator JsValue(double value)
|
|
{
|
|
{
|
|
- return FromDouble(value);
|
|
|
|
|
|
+ return JsNumber.Create(value);
|
|
}
|
|
}
|
|
|
|
|
|
public static implicit operator JsValue(bool value)
|
|
public static implicit operator JsValue(bool value)
|
|
{
|
|
{
|
|
- return value ? True : False;
|
|
|
|
|
|
+ return value ? JsBoolean.True : JsBoolean.False;
|
|
}
|
|
}
|
|
|
|
|
|
public static implicit operator JsValue(string value)
|
|
public static implicit operator JsValue(string value)
|
|
{
|
|
{
|
|
- if (value.Length <= 1)
|
|
|
|
- {
|
|
|
|
- if (value == "")
|
|
|
|
- {
|
|
|
|
- return EmptyString;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (value.Length == 1)
|
|
|
|
- {
|
|
|
|
- if (value[0] >= 0 && value[0] <= AsciiMax)
|
|
|
|
- {
|
|
|
|
- return _charToStringJsValue[value[0]];
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ return JsString.Create(value);
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ public override bool Equals(object obj)
|
|
|
|
+ {
|
|
|
|
+ if (ReferenceEquals(null, obj))
|
|
|
|
+ {
|
|
|
|
+ return false;
|
|
}
|
|
}
|
|
- else if (value == Native.Null.Text)
|
|
|
|
|
|
+
|
|
|
|
+ if (ReferenceEquals(this, obj))
|
|
{
|
|
{
|
|
- return NullString;
|
|
|
|
|
|
+ return true;
|
|
}
|
|
}
|
|
|
|
|
|
- return new JsValue(value);
|
|
|
|
|
|
+ return obj is JsValue value && Equals(value);
|
|
}
|
|
}
|
|
|
|
|
|
- public static implicit operator JsValue(ObjectInstance value)
|
|
|
|
|
|
+ public abstract bool Equals(JsValue other);
|
|
|
|
+
|
|
|
|
+ public override int GetHashCode()
|
|
{
|
|
{
|
|
- return value.JsValue;
|
|
|
|
|
|
+ return Type.GetHashCode();
|
|
}
|
|
}
|
|
|
|
|
|
internal class JsValueDebugView
|
|
internal class JsValueDebugView
|
|
{
|
|
{
|
|
public string Value;
|
|
public string Value;
|
|
|
|
+
|
|
public JsValueDebugView(JsValue value)
|
|
public JsValueDebugView(JsValue value)
|
|
{
|
|
{
|
|
-
|
|
|
|
switch (value.Type)
|
|
switch (value.Type)
|
|
{
|
|
{
|
|
case Types.None:
|
|
case Types.None:
|
|
@@ -880,34 +453,5 @@ namespace Jint.Native
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
- public override bool Equals(object obj)
|
|
|
|
- {
|
|
|
|
- if (ReferenceEquals(null, obj)) return false;
|
|
|
|
- return obj is JsValue value && Equals(value);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public override int GetHashCode()
|
|
|
|
- {
|
|
|
|
- unchecked
|
|
|
|
- {
|
|
|
|
- var hashCode = 0;
|
|
|
|
- hashCode = (hashCode * 397) ^ _double.GetHashCode();
|
|
|
|
- hashCode = (hashCode * 397) ^ (_object != null ? _object.GetHashCode() : 0);
|
|
|
|
- hashCode = (hashCode * 397) ^ (int)_type;
|
|
|
|
- return hashCode;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /// <summary>
|
|
|
|
- /// The _object value of a <see cref="JsSymbol"/> is the [[Description]] internal slot.
|
|
|
|
- /// </summary>
|
|
|
|
- public class JsSymbol : JsValue
|
|
|
|
- {
|
|
|
|
- public JsSymbol(string description) : base(description)
|
|
|
|
- {
|
|
|
|
- _type = Types.Symbol;
|
|
|
|
- }
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|