Пример #1
0
        public JurassicJsEngine(object global)
        {
            _typeConverter = new ClrTypeConverter(new ScriptEngine(), () => _global);

            if (global != null)
            {
	            _global = global;
	            Engine.Global.DefineProperties(_typeConverter, global.GetType(), global);
	            foreach (var method in _global.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance))
	            {
		            var ctor = method.GetCustomAttribute<JsCtorAttribute>();
		            if(ctor == null)
			            continue;

		            var paramConverter = ClrTypeConverter.GetParamsConverter(_typeConverter, method.GetParameters());
		            
		            var prototype = _typeConverter.GetPrototype(method.ReturnType);
		            var jsCtor = new ClrCtor(_typeConverter, method.ReturnType, prototype, ctor.Name, args =>
		            {
			            var clrArgs = paramConverter(Engine.Global, args);
			            return method.Invoke(global, clrArgs);
		            });
            
		            _typeConverter.Engine.SetGlobalValue(ctor.Name, jsCtor);
	            }
            }
        }
Пример #2
0
        public override object CallLateBound(object thisObject, params object[] argumentValues)
        {
            var clrObject = thisObject is Undefined ? _owner : _ctx.ConvertToClr(thisObject);

            var methodIndex = _methods.IndexOf(x => x.GetParameters().IsAppropriate(argumentValues));

            if (methodIndex < 0)
            {
                return(null); //or throw exception;
            }
            var method = _methods[methodIndex];

            var converter = _paramConverters[methodIndex] ?? (_paramConverters[methodIndex] =
                                                                  ClrTypeConverter.GetParamsConverter(_ctx, method.GetParameters()));

            var clrArguments = converter(thisObject, argumentValues);

            try
            {
                var clrResult = method.Invoke(clrObject, clrArguments);
                return(_ctx.ConvertToJs(clrResult));
            }
            catch (Exception e)
            {
                throw new JavaScriptException(_ctx.Engine, ErrorType.Error, e.Message, e);
            }
        }
Пример #3
0
	    public ClrPrototype(ClrTypeConverter ctx, Type type) : base(ctx.Engine, ctx.GetPrototype(type.BaseType))
	    {
		    var name = type.GetCustomAttribute<JsNameAttribute>()?.Name ?? type.Name;
		    this[ctx.Engine.Symbol.ToStringTag] = name;
		    this.DefineProperties(ctx, type);
		    Name = name;
	    }
Пример #4
0
        public static bool IsAppropriate(this ParameterInfo[] pars, object[] argumentValues)
        {
            var isParamArray = pars.Length > 0 && pars.Last().GetCustomAttribute <ParamArrayAttribute>() != null;

            var checkLength = isParamArray ? pars.Length - 1 : pars.Length;

            for (var idx = 0; idx < checkLength; idx++)
            {
                var par = pars[idx];

                if (idx >= argumentValues.Length && !par.HasDefaultValue)
                {
                    return(false);
                }

                if (!ClrTypeConverter.CanConvert(argumentValues[idx], par.ParameterType))
                {
                    return(false);
                }
            }

            if (isParamArray && argumentValues.Length > checkLength)
            {
                var elementType = pars.Last().ParameterType.GetElementType();
                return(argumentValues.Skip(checkLength).All(x => ClrTypeConverter.CanConvert(x, elementType)));
            }

            return(true);
        }
Пример #5
0
 public ClrCtor(ClrTypeConverter ctx, Type type, ObjectInstance prototype, string name, Func<object[], object> creator)
     : base(ctx.Engine.Function.InstancePrototype, name, prototype)
 {
     _ctx = ctx;
     _creator = creator;
     this.DefineStaticProperties(ctx, type);
 }
Пример #6
0
        public object CallMethod(ClrTypeConverter ctx, MethodInfo method, object thisObject,
                                 object[] argumentValues, object clrObject)
        {
            if (thisObject is ClrPrototype proto)
            {
                if (method.Name == "ToString")
                {
                    return($"[object {proto.Name}]");
                }

                throw new JavaScriptException(ctx.Engine, ErrorType.Error, "Illegal method invocation.");
            }

            var clrArguments = _paramsConverter(thisObject, argumentValues);

            try
            {
                var clrResult = method.Invoke(clrObject, clrArguments);
                return(ctx.ConvertToJs(clrResult));
            }
            catch (Exception e)
            {
                throw new JavaScriptException(ctx.Engine, ErrorType.Error, e.Message, e);
            }
        }
Пример #7
0
 public ClrOverloadMethodInstance(ClrTypeConverter ctx, object owner, MethodInfo[] methods, string name) : base(ctx.Engine)
 {
     _ctx             = ctx;
     _owner           = owner;
     _methods         = methods.OrderByDescending(x => x.GetParameters().Length).ToArray();
     _paramConverters = new Func <object, object[], object[]> [methods.Length];
     SetPropertyValue("name", name, false);
 }
Пример #8
0
        public ClrMethodInstance(ClrTypeConverter ctx, object owner, MethodInfo method, string name) : base(ctx.Engine)
        {
            _ctx             = ctx;
            _owner           = owner;
            _method          = method;
            _paramsConverter = ClrTypeConverter.GetParamsConverter(_ctx, _method.GetParameters());

            SetPropertyValue("name", name, false);
        }
Пример #9
0
        public static Func <object, object[], object[]> GetParamsConverter(ClrTypeConverter ctx, ParameterInfo[] methodParameters)
        {
            if (methodParameters.Length > 0)
            {
                var lastParameter = methodParameters.Last();

                //have a deal with 'param'
                if (lastParameter.GetCustomAttribute <ParamArrayAttribute>() != null)
                {
                    return((thisObject, argumentValues) =>
                    {
                        if (argumentValues.Length < methodParameters.Length)
                        {
                            return ctx.ConvertParametersToClr(methodParameters, thisObject, argumentValues);
                        }

                        var part1Types = methodParameters.Take(methodParameters.Length - 1).ToArray();
                        var clrArgumentsPart1 = ctx.ConvertParametersToClr(part1Types, thisObject, argumentValues);

                        var part2Types = Enumerable
                                         .Repeat(typeof(object), argumentValues.Length - part1Types.Length)
                                         .ToArray();

                        var clrArgumentsPart2 = ctx.ConvertParametersToClr(part2Types, thisObject,
                                                                           argumentValues.Skip(part1Types.Length).ToArray());

                        var clrArguments = new object[methodParameters.Length];

                        Array.Copy(clrArgumentsPart1, clrArguments, clrArgumentsPart1.Length);
                        clrArguments[clrArguments.Length - 1] = clrArgumentsPart2;
                        return clrArguments;
                    });
                }

                var expands = methodParameters
                              .Select(parameterInfo => parameterInfo.GetCustomAttribute <JsExpandArrayAttribute>() != null)
                              .ToArray();

                var hasExpands = expands.Any(x => x);

                if (hasExpands || methodParameters.Any(x => !x.ParameterType.IsValueType))
                {
                    return((thisObject, argumentValues) =>
                           ctx.ConvertParametersToClr(methodParameters, thisObject, argumentValues));
                }


                //Simple case with value parameters.
                var converters =
                    methodParameters.Select(x => ctx.GetConverter(x.ParameterType, x.GetDefaultValue()));

                return((thisObject, args) => converters.Select((c, i) => c(i < args.Length ? args[i]: null))
                       .ToArray());
            }

            return((_, __) => new object[0]);
        }
Пример #10
0
        public static void DefineStaticProperties(this ObjectInstance jsObject, ClrTypeConverter ctx, Type type)
        {
            foreach (var staticField in type.GetFields(BindingFlags.Public | BindingFlags.Static)
                     .Where(p => p.GetCustomAttribute <JsHiddenAttribute>() == null))
            {
                var clrValue = staticField.GetValue(null);
                var prop     = new PropertyDescriptor(ctx.ConvertToJs(clrValue), PropertyAttributes.Sealed);

                var name = staticField.GetCustomAttribute <JsNameAttribute>()?.Name ?? staticField.Name;

                jsObject.DefineProperty(name, prop, false);
            }
        }
Пример #11
0
        public static object[] ConvertParametersToClr(this ClrTypeConverter ctx, ParameterInfo[] methodParameters,
                                                      object thisObject,
                                                      object[] argumentValues)
        {
            var clrArguments = new object[methodParameters.Length];

            for (var idx = 0; idx < clrArguments.Length; idx++)
            {
                var par = methodParameters[idx];

                if (idx < argumentValues.Length)
                {
                    //todo: optimize
                    var expand = par.GetCustomAttribute <JsExpandArrayAttribute>() != null;

                    var jsArgument = argumentValues[idx];

                    if (!expand && (par.ParameterType.IsValueType))
                    {
                        clrArguments[idx] = ctx.GetConverter(par.ParameterType, par.GetDefaultValue())(jsArgument);
                    }
                    else
                    {
                        clrArguments[idx] =
                            ctx.ConvertToClr(
                                jsArgument,
                                par.ParameterType,
                                thisObject,
                                expand);
                    }
                }
                else
                {
                    if (par.GetCustomAttribute <ParamArrayAttribute>() != null)
                    {
                        clrArguments[idx] = Activator.CreateInstance(par.ParameterType, 0);
                    }
                    else if (par.HasDefaultValue)
                    {
                        clrArguments[idx] = par.DefaultValue;
                    }
                }
            }

            return(clrArguments);
        }
Пример #12
0
        public static object[] ConvertParametersToClr(this ClrTypeConverter ctx, Type[] methodParameters,
                                                      object thisObject,
                                                      object[] argumentValues)
        {
            var clrArguments = new object[methodParameters.Length];

            for (var idx = 0; idx < clrArguments.Length; idx++)
            {
                if (idx < argumentValues.Length)
                {
                    var jsArgument = argumentValues[idx];
                    clrArguments[idx] = ctx.ConvertToClr(jsArgument, methodParameters[idx], thisObject);
                }
            }

            return(clrArguments);
        }
Пример #13
0
        public ClrObjectInstance(ClrTypeConverter ctx, object obj, ObjectInstance prototype) : base(prototype)
        {
            var type = obj.GetType();

            this[ctx.Engine.Symbol.ToStringTag] = type.GetCustomAttribute <JsNameAttribute>()?.Name ?? type.Name;

            _ctx   = ctx;
            Target = obj;

            if (Target is Array array)
            {
                _array = array;
            }
            else
            {
                _indexProperties = Target.GetType()
                                   .GetProperties(BindingFlags.Instance | BindingFlags.Public)
                                   .Where(x => x.GetIndexParameters().Length == 1)
                                   .ToArray();
            }
        }
Пример #14
0
        /// <summary>
        /// Adds properties to the specified js object from the specified clr object.
        /// </summary>
        public static void DefineProperties(this ObjectInstance jsObject, ClrTypeConverter ctx, Type type, object clrOwner = null)
        {
            var bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly;

            //register properties
            foreach (var property in type.GetProperties(bindingFlags).Where(p => p.GetCustomAttribute <JsHiddenAttribute>() == null))
            {
                var name = property.GetName();

                //todo: compile delegate instead of reflection, research what is faster.

                var jsGetter =
                    property.GetMethod != null && property.GetMethod.IsPublic ? new FuncInst(ctx, clrThis => property.GetValue(clrThis)) : null;

                var jsSetter =
                    property.SetMethod != null && property.SetMethod.IsPublic ? new ActInst(ctx, (clrThis, objects) =>
                                                                                            property.SetValue(clrThis, ctx.ConvertToClr(objects[0], property.PropertyType, ctx.ConvertToJs(clrThis)))) : null;

                var jsProperty = new PropertyDescriptor(jsGetter, jsSetter, PropertyAttributes.Configurable);

                jsObject.DefineProperty(name, jsProperty, false);
            }

            //register methods
            foreach (var methods in type
                     .GetMethods(bindingFlags)
                     .Where(p => p.GetCustomAttribute <JsHiddenAttribute>() == null &&
                            p.GetCustomAttribute <JsCtorAttribute>() == null)
                     .GroupBy(p => p.GetName()))
            {
                var methodsArray = methods.ToArray();

                var firstMethod = methodsArray[0];

                if (firstMethod.IsSpecialName)
                {
                    continue;
                }

                if (firstMethod.DeclaringType == typeof(object))
                {
                    continue;
                }

                var name = methods.Key;

                var jsMethod =
                    methodsArray.Length == 1
                        ? new ClrMethodInstance(ctx, clrOwner, firstMethod, name)
                        : (FunctionInstance) new ClrOverloadMethodInstance(ctx, clrOwner, methodsArray, name);

                //todo: check the PropertyAttributes
                var jsProperty = new PropertyDescriptor(jsMethod, PropertyAttributes.Sealed);

                jsObject.DefineProperty(name, jsProperty, false);
            }

            //register events
            foreach (var evt in type.GetEvents(bindingFlags)
                     .Where(p => p.GetCustomAttribute <JsHiddenAttribute>() == null))
            {
                var name = evt.GetName().ToLowerInvariant();

                var jsGetter = new FuncInst(ctx, clrThis =>
                {
                    var attachedEvents = ctx.GetAttachedEventsFor(clrThis);
                    return(attachedEvents[evt]);
                }, false);

                var jsSetter = new ActInst(ctx,
                                           (clrThis, args) =>
                {
                    var jsThis = ctx.ConvertToJs(clrThis);

                    var attachedEvents = ctx.GetAttachedEventsFor(clrThis);

                    if (attachedEvents.TryGetValue(evt, out var existHandler))
                    {
                        var clrHandler = ctx.ConvertToClr(existHandler, evt.EventHandlerType, jsThis);
                        evt.RemoveMethod.Invoke(clrThis, new [] { clrHandler });
                        attachedEvents.Remove(evt);
                    }

                    if (args.Length != 0 && args[0] is FunctionInstance functionInstance)
                    {
                        var clrHandler = ctx.ConvertToClr(args[0], evt.EventHandlerType, jsThis);
                        evt.AddMethod.Invoke(clrThis, new[] { clrHandler });
                        attachedEvents[evt] = functionInstance;
                    }
                });

                var jsProperty = new PropertyDescriptor(jsGetter, jsSetter, PropertyAttributes.Configurable);

                jsObject.DefineProperty(name, jsProperty, false);
            }

            //Register static fields
            DefineStaticProperties(jsObject, ctx, type);
        }
Пример #15
0
 public ActInst(ClrTypeConverter ctx, Action <object, object[]> act) : base(ctx.Engine)
 {
     _ctx = ctx;
     _act = act;
 }
Пример #16
0
 public FuncInst(ClrTypeConverter ctx, Func <object, object> func, bool doConvert = true) : base(ctx.Engine)
 {
     _ctx       = ctx;
     _func      = func;
     _doConvert = doConvert;
 }