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); } }
protected override object GetMissingPropertyValue(object key) { if (_array != null) { switch (key) { case int index: return(_ctx.ConvertToJs(_array.GetValue(index))); case string str: return(int.TryParse(str, out var parsedIndex) && parsedIndex >= 0 && parsedIndex < _array.Length ? _ctx.ConvertToJs(_array.GetValue(parsedIndex)) : base.GetMissingPropertyValue(key)); default: return(base.GetMissingPropertyValue(key)); } } var clrKey = _ctx.ConvertToClr(key); var pi = clrKey == null ? _indexProperties.FirstOrDefault(x => x.GetIndexParameters()[0].ParameterType.CanBeNull()) : _indexProperties.FirstOrDefault(x => x.GetIndexParameters()[0].ParameterType.IsInstanceOfType(clrKey)); //converts string key to integer. if (pi == null && key is string stringKey) { pi = _indexProperties.FirstOrDefault(x => x.GetIndexParameters()[0].ParameterType == typeof(int)); if (pi != null) { if (int.TryParse(stringKey, out var idx)) { clrKey = idx; } else { return(base.GetMissingPropertyValue(key)); } } else { pi = _indexProperties.FirstOrDefault(x => x.GetIndexParameters()[0].ParameterType == typeof(ulong)); if (ulong.TryParse(stringKey, out var idx)) { clrKey = idx; } else { return(base.GetMissingPropertyValue(key)); } } } return(pi != null ? _ctx.ConvertToJs(pi.GetValue(Target, new[] { clrKey })) : base.GetMissingPropertyValue(key)); }
public override object CallLateBound(object thisObject, params object[] argumentValues) { var clrObject = thisObject is global::Jurassic.Undefined ? _owner : _ctx.ConvertToClr(thisObject); //todo: investigate if the precompiled expression can be faster than reflection invoke. return(CallMethod(_ctx, _method, thisObject, argumentValues, clrObject)); }
public object Evaluate(string code) { try { return _typeConverter.ConvertToClr(Engine.Evaluate(Clean(code))); } catch (JavaScriptException e) { return new ScriptExecutingException(e.Message, e, code); } }
public override object CallLateBound(object thisObject, params object[] argumentValues) { try { var clrThis = _ctx.ConvertToClr(thisObject); return(_doConvert ? _ctx.ConvertToJs(_func(clrThis)) : _func(clrThis)); } catch (Exception e) { throw new JavaScriptException(_ctx.Engine, ErrorType.Error, e.Message, e); } }
public override object CallLateBound(object thisObject, params object[] argumentValues) { try { var clrThis = _ctx.ConvertToClr(thisObject); _act(clrThis, argumentValues); } catch (Exception e) { throw new JavaScriptException(Engine, ErrorType.Error, e.Message, e); } return(null); }
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); }
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); }
/// <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); }