private ReactMethodImpl MakeReturningMethod(ReflectionMethodInfo methodInfo, Type returnType, ParameterInfo[] parameters) { // It is like the MakeCallbackMethod but callback is not passed as a parameter. // Input parameters for generated lambda ParameterExpression moduleParameter = Expression.Parameter(typeof(object), "module"); ParameterExpression inputReaderParameter = Expression.Parameter(typeof(IJSValueReader), "inputReader"); ParameterExpression outputWriterParameter = Expression.Parameter(typeof(IJSValueWriter), "outputWriter"); ParameterExpression resolveParameter = Expression.Parameter(typeof(MethodResultCallback), "resolve"); ParameterExpression rejectParameter = Expression.Parameter(typeof(MethodResultCallback), "reject"); // Input variables to read from inputReader ParameterExpression[] inputVariables = new ParameterExpression[parameters.Length]; for (int i = 0; i < parameters.Length; ++i) { inputVariables[i] = Expression.Variable(parameters[i].ParameterType, parameters[i].Name); } // The result variable to store method call result var resultVariable = Expression.Variable(returnType); // Statements of the generated lambda List <Expression> statements = new List <Expression>(); // Generate code to read input variables from the inputReader var callReadNext = Expression.Call(inputReaderParameter, typeof(IJSValueReader).GetMethod("ReadNext")); statements.Add(callReadNext); foreach (ParameterExpression variable in inputVariables) { statements.Add(callReadNext); statements.Add(Expression.Call(null, JSValueReader.GetReadValueMethod(variable.Type), inputReaderParameter, variable)); } // Generate code to call the method statements.Add(Expression.Assign(resultVariable, Expression.Call( Expression.Convert(moduleParameter, methodInfo.DeclaringType), methodInfo, inputVariables))); // Generate code to write result to outputWriter statements.Add(Expression.Call(outputWriterParameter, typeof(IJSValueWriter).GetMethod("WriteArrayBegin"))); statements.Add(Expression.Call(null, JSValueWriter.GetWriteValueMethod(resultVariable.Type), outputWriterParameter, resultVariable)); statements.Add(Expression.Call(outputWriterParameter, typeof(IJSValueWriter).GetMethod("WriteArrayEnd"))); // Generate code to call resolve callback statements.Add(Expression.Invoke(resolveParameter, outputWriterParameter)); // Generate the lambda to return var lambda = Expression.Lambda <ReactMethodImpl>( Expression.Block(inputVariables.Append(resultVariable), statements), moduleParameter, inputReaderParameter, outputWriterParameter, resolveParameter, rejectParameter); // Compile and return the lambda return(lambda.Compile()); }
private ReactConstantImpl MakePropertyConstant(PropertyInfo propertyInfo) { ParameterExpression moduleParameter = Expression.Parameter(typeof(object), "module"); ParameterExpression writerParameter = Expression.Parameter(typeof(IJSValueWriter), "writer"); bool isStatic = propertyInfo.GetGetMethod().IsStatic; Type propertyType = propertyInfo.PropertyType; var constantProperty = Expression.Property(isStatic ? null : Expression.Convert(moduleParameter, propertyInfo.DeclaringType), propertyInfo); var writeValueCall = Expression.Call(null, JSValueWriter.GetWriteValueMethod(propertyType), writerParameter, constantProperty); var lambda = Expression.Lambda <ReactConstantImpl>(writeValueCall, moduleParameter, writerParameter); return(lambda.Compile()); }
private ReactConstantImpl MakeFieldConstant(FieldInfo fieldInfo) { ParameterExpression moduleParameter = Expression.Parameter(typeof(object), "module"); ParameterExpression writerParameter = Expression.Parameter(typeof(IJSValueWriter), "writer"); bool isStatic = fieldInfo.IsStatic; Type fieldType = fieldInfo.FieldType; var constantField = Expression.Field(isStatic ? null : Expression.Convert(moduleParameter, fieldInfo.DeclaringType), fieldInfo); var writeValueCall = Expression.Call(null, JSValueWriter.GetWriteValueMethod(fieldType), writerParameter, constantField); var lambda = Expression.Lambda <ReactConstantImpl>(writeValueCall, moduleParameter, writerParameter); return(lambda.Compile()); }
private ReactEventImpl MakeEvent(PropertyInfo propertyInfo, ParameterInfo parameter) { // We need to create a delegate that can assign correct delegate to the event property. // This is the shape of the generated code: // //(object module, RaiseEvent raiseEvent) => //{ // ((MyModule)module).eventProperty = (ArgType arg) => // { // raiseEvent((IJSValueWriter argWriter) => WriteValue(argWriter, arg)); // }; //}); // // Input parameters for generated lambda ParameterExpression moduleParameter = Expression.Parameter(typeof(object), "module"); ParameterExpression raiseEventParameter = Expression.Parameter(typeof(ReactEventHandler), "eventHandler"); // Create a lambda to be passed to raiseEvent ParameterExpression argParameter = Expression.Parameter(parameter.ParameterType, "arg"); ParameterExpression argWriterParameter = Expression.Parameter(typeof(IJSValueWriter), "argWriter"); var writeValueCall = Expression.Call(null, JSValueWriter.GetWriteValueMethod(parameter.ParameterType), argWriterParameter, argParameter); var eventHandlerLambda = Expression.Lambda <ReactArgWriter>(writeValueCall, argWriterParameter); // Create a lambda that we assign to the event property var raiseEventCall = Expression.Invoke(raiseEventParameter, eventHandlerLambda); var eventLambda = Expression.Lambda(propertyInfo.PropertyType, raiseEventCall, argParameter); // Create lambda that we return and which assigns the event property var eventProperty = Expression.Property(Expression.Convert(moduleParameter, propertyInfo.DeclaringType), propertyInfo); var eventPropertyAssignment = Expression.Assign(eventProperty, eventLambda); var lambda = Expression.Lambda <ReactEventImpl>(eventPropertyAssignment, moduleParameter, raiseEventParameter); // Compile and return the lambda return(lambda.Compile()); }
private ReactMethodImpl MakeCallbackMethod(ReflectionMethodInfo methodInfo, ParameterInfo[] parameters) { // The last variable is a delegate // Input parameters for generated lambda ParameterExpression moduleParameter = Expression.Parameter(typeof(object), "module"); ParameterExpression inputReaderParameter = Expression.Parameter(typeof(IJSValueReader), "inputReader"); ParameterExpression outputWriterParameter = Expression.Parameter(typeof(IJSValueWriter), "outputWriter"); ParameterExpression resolveParameter = Expression.Parameter(typeof(MethodResultCallback), "resolve"); ParameterExpression rejectParameter = Expression.Parameter(typeof(MethodResultCallback), "reject"); // Input variables to read from inputReader ParameterExpression[] inputVariables = new ParameterExpression[parameters.Length - 1]; for (int i = 0; i < inputVariables.Length; ++i) { inputVariables[i] = Expression.Variable(parameters[i].ParameterType, parameters[i].Name); } // Generate the resolve delegate var inputResolveParameter = parameters[parameters.Length - 1]; var resolveMethodInfo = inputResolveParameter.ParameterType.GetMethod("Invoke"); ParameterInfo[] resolveMethodParameters = resolveMethodInfo.GetParameters(); if (resolveMethodParameters.Length != 1) { throw new ArgumentException($"Resolve callback type must have one parameter. Method: {MethodName}, Parameter: {inputResolveParameter.Name}"); } Type resolveParameterType = resolveMethodParameters[0].ParameterType; ParameterExpression resolveLambdaParameter = Expression.Parameter(resolveParameterType, "value"); List <Expression> resolveStatements = new List <Expression>(); resolveStatements.Add(Expression.Call(outputWriterParameter, typeof(IJSValueWriter).GetMethod("WriteArrayBegin"))); resolveStatements.Add(Expression.Call(null, JSValueWriter.GetWriteValueMethod(resolveParameterType), outputWriterParameter, resolveLambdaParameter)); resolveStatements.Add(Expression.Call(outputWriterParameter, typeof(IJSValueWriter).GetMethod("WriteArrayEnd"))); resolveStatements.Add(Expression.Invoke(resolveParameter, outputWriterParameter)); var resolveLambda = Expression.Lambda(inputResolveParameter.ParameterType, Expression.Block(resolveStatements), resolveLambdaParameter); // Statements of the generated lambda List <Expression> statements = new List <Expression>(); // Generate code to read input variables from the inputReader var callReadNext = Expression.Call(inputReaderParameter, typeof(IJSValueReader).GetMethod("ReadNext")); statements.Add(callReadNext); foreach (ParameterExpression variable in inputVariables) { statements.Add(callReadNext); statements.Add(Expression.Call(null, JSValueReader.GetReadValueMethod(variable.Type), inputReaderParameter, variable)); } // Generate code to call the method statements.Add(Expression.Call( Expression.Convert(moduleParameter, methodInfo.DeclaringType), methodInfo, (inputVariables as IEnumerable <Expression>).Append(resolveLambda))); // Generate the lambda to return var lambda = Expression.Lambda <ReactMethodImpl>( Expression.Block(inputVariables, statements), moduleParameter, inputReaderParameter, outputWriterParameter, resolveParameter, rejectParameter); // Compile and return the lambda return(lambda.Compile()); }