/Microsoft.Scripting/Actions/Calls/KeywordConstructorReturnBuilder.cs
C# | 142 lines | 109 code | 14 blank | 19 comment | 10 complexity | 8cc64fcb33727cee91c56cb72aa3b247 MD5 | raw file
- /* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Microsoft Public License. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Microsoft Public License, please send an email to
- * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
- * by the terms of the Microsoft Public License.
- *
- * You must not remove this notice, or any other, from this software.
- *
- *
- * ***************************************************************************/
-
- #if CODEPLEX_40
- using System;
- #else
- using System; using Microsoft;
- #endif
- using System.Collections.Generic;
- #if CODEPLEX_40
- using System.Linq.Expressions;
- #else
- using Microsoft.Linq.Expressions;
- #endif
- using System.Reflection;
- using Microsoft.Scripting.Runtime;
- using AstUtils = Microsoft.Scripting.Ast.Utils;
-
- namespace Microsoft.Scripting.Actions.Calls {
- #if CODEPLEX_40
- using Ast = System.Linq.Expressions.Expression;
- #else
- using Ast = Microsoft.Linq.Expressions.Expression;
- #endif
-
- /// <summary>
- /// Updates fields/properties of the returned value with unused keyword parameters.
- /// </summary>
- class KeywordConstructorReturnBuilder : ReturnBuilder {
- private readonly ReturnBuilder _builder;
- private readonly int _kwArgCount;
- private readonly int[] _indexesUsed;
- private readonly MemberInfo[] _membersSet;
- private readonly bool _privateBinding;
-
- public KeywordConstructorReturnBuilder(ReturnBuilder builder, int kwArgCount, int[] indexesUsed, MemberInfo[] membersSet,
- bool privateBinding)
- : base(builder.ReturnType) {
- _builder = builder;
- _kwArgCount = kwArgCount;
- _indexesUsed = indexesUsed;
- _membersSet = membersSet;
- _privateBinding = privateBinding;
- }
-
- internal override Expression ToExpression(ParameterBinder parameterBinder, IList<ArgBuilder> args, IList<Expression> parameters, Expression ret) {
- List<Expression> sets = new List<Expression>();
-
- ParameterExpression tmp = parameterBinder.GetTemporary(ret.Type, "val");
- sets.Add(
- Ast.Assign(tmp, ret)
- );
-
- for (int i = 0; i < _indexesUsed.Length; i++) {
- Expression value = parameters[parameters.Count - _kwArgCount + _indexesUsed[i]];
- switch(_membersSet[i].MemberType) {
- case MemberTypes.Field:
- FieldInfo fi = (FieldInfo)_membersSet[i];
- if (!fi.IsLiteral && !fi.IsInitOnly) {
- sets.Add(
- Ast.Assign(
- Ast.Field(tmp, fi),
- ConvertToHelper(parameterBinder, value, fi.FieldType)
- )
- );
- } else {
- // call a helper which throws the error but "returns object"
- sets.Add(
- Ast.Convert(
- Ast.Call(
- typeof(ScriptingRuntimeHelpers).GetMethod("ReadOnlyAssignError"),
- AstUtils.Constant(true),
- AstUtils.Constant(fi.Name)
- ),
- fi.FieldType
- )
- );
- }
- break;
-
- case MemberTypes.Property:
- PropertyInfo pi = (PropertyInfo)_membersSet[i];
- if (pi.GetSetMethod(_privateBinding) != null) {
- sets.Add(
- Ast.Assign(
- Ast.Property(tmp, pi),
- ConvertToHelper(parameterBinder, value, pi.PropertyType)
- )
- );
- } else {
- // call a helper which throws the error but "returns object"
- sets.Add(
- Ast.Convert(
- Ast.Call(
- typeof(ScriptingRuntimeHelpers).GetMethod("ReadOnlyAssignError"),
- AstUtils.Constant(false),
- AstUtils.Constant(pi.Name)
- ),
- pi.PropertyType
- )
- );
- }
- break;
- }
- }
-
- sets.Add(
- tmp
- );
-
- Expression newCall = Ast.Block(
- sets.ToArray()
- );
-
- return _builder.ToExpression(parameterBinder, args, parameters, newCall);
- }
-
- private static Expression ConvertToHelper(ParameterBinder parameterBinder, Expression value, Type type) {
- if (type == value.Type) {
- return value;
- }
-
- if (type.IsAssignableFrom(value.Type)) {
- return AstUtils.Convert(value, type);
- }
-
- return parameterBinder.GetDynamicConversion(value, type);
- }
- }
- }