private static JsFunction WrapSetFieldCore(FieldInfo field) { if (field == null) throw new ArgumentNullException("field"); var builder = new Builder(); builder.AddRuntimeParameter(); builder.AddThisParameter(typeof(object)); builder.AddParameter(typeof(JsObject), "callee"); var argumentsParameter = builder.AddParameter(typeof(object[]), "arguments"); var local = builder.AddLocal(typeof(object), "value"); builder.AddStatement(Expression.Assign( local, Expression.ArrayAccess( argumentsParameter, Expression.Constant(0) ) )); // Can't assign to constants. if (!field.IsLiteral && !field.IsInitOnly) { builder.AddStatement(Expression.Assign( Expression.Field( builder.MarshalThis(field.DeclaringType, field.IsStatic), field ), builder.Marshal(local, field.FieldType) )); } builder.AddStatement(local); return builder.Compile<JsFunction>(); }
private static JsFunction WrapSetPropertyCore(PropertyInfo property) { var builder = new Builder(); builder.AddRuntimeParameter(); builder.AddThisParameter(typeof(object)); builder.AddParameter(typeof(JsObject), "callee"); var argumentsParameter = builder.AddParameter(typeof(object[]), "arguments"); var method = property.GetSetMethod(); var local = builder.AddLocal(typeof(object), "value"); builder.AddStatement(Expression.Assign( local, Expression.ArrayAccess( argumentsParameter, Expression.Constant(0) ) )); builder.AddStatement(Expression.Assign( Expression.Property( builder.MarshalThis(method.DeclaringType, method.IsStatic), property ), builder.Marshal( local, property.PropertyType ) )); builder.AddStatement(local); return builder.Compile<JsFunction>(); }
private static JsFunction WrapMethodCore(MethodInfo method) { var builder = new Builder(); builder.AddRuntimeParameter(); builder.AddThisParameter(typeof(object)); builder.AddParameter(typeof(JsObject), "callee"); var argumentsParameter = builder.AddParameter(typeof(object[]), "arguments"); var methodThis = builder.MarshalThis(method.DeclaringType, method.IsStatic); var arguments = new List<Expression>(); var parameters = method.GetParameters(); bool skipFirst = false; if (parameters.Length > 0 && typeof(JsGlobal).IsAssignableFrom(parameters[0].ParameterType)) { skipFirst = true; arguments.Add(builder.Global); } var outParameters = new List<Tuple<ParameterInfo, ParameterExpression, int>>(); int index = 0; foreach (var parameter in parameters) { // Skip over the global parameter. if (skipFirst) { skipFirst = false; continue; } // Get the argument from the array, or undefined there is none. Expression argument = Expression.Condition( Expression.GreaterThan( Expression.ArrayLength(argumentsParameter), Expression.Constant(index) ), Expression.ArrayAccess( argumentsParameter, Expression.Constant(index) ), Expression.Field(null, typeof(JsUndefined).GetField("Instance")), typeof(object) ); // If this is a ref or out parameter, we need to create a local. if (parameter.ParameterType.IsByRef) { var parameterType = parameter.ParameterType.GetElementType(); argument = builder.Marshal(argument, parameterType); // Create a local to hold the value. var tmpLocal = builder.AddLocal( parameterType, "tmp" ); // Add the assignment to the statements. builder.AddStatement(Expression.Assign(tmpLocal, argument)); // And use the temp local as the parameter. argument = tmpLocal; // Register it so that we do a write-back later on. outParameters.Add(Tuple.Create(parameter, tmpLocal, index)); } else { argument = builder.Marshal(argument, parameter.ParameterType); } // Add the argument to the list. arguments.Add(argument); // Move on to the next argument. index++; } // Call the method. Expression methodCall = Expression.Call( methodThis, method, arguments ); // Are we returning a value? ParameterExpression returnLocal = null; if (method.ReturnType != typeof(void)) { returnLocal = builder.AddLocal(method.ReturnType, "return"); methodCall = Expression.Assign( returnLocal, methodCall ); } // Add the method call to the statements. builder.AddStatement(methodCall); // Process any out parameters. foreach (var outParameter in outParameters) { // Put the result back into the arguments array if the array // is long enough. builder.AddStatement(Expression.IfThen( Expression.GreaterThan( Expression.ArrayLength(argumentsParameter), Expression.Constant(outParameter.Item3) ), Expression.Assign( Expression.ArrayAccess( argumentsParameter, Expression.Constant(outParameter.Item3) ), Expression.Call( builder.Marshaller, _marshalClr.MakeGenericMethod(outParameter.Item1.ParameterType.GetElementType()), outParameter.Item2 ) ) )); } // Create the result. builder.AddStatement( returnLocal != null ? builder.UnMarshal(returnLocal, method.ReturnType) : Expression.Field(null, typeof(JsUndefined).GetField("Instance")) ); return builder.Compile<JsFunction>(); }