PageRenderTime 123ms CodeModel.GetById 80ms app.highlight 8ms RepoModel.GetById 33ms app.codeStats 0ms

/Microsoft.Scripting/Actions/Calls/KeywordConstructorReturnBuilder.cs

https://bitbucket.org/stefanrusek/xronos
C# | 142 lines | 109 code | 14 blank | 19 comment | 10 complexity | 8cc64fcb33727cee91c56cb72aa3b247 MD5 | raw file
  1/* ****************************************************************************
  2 *
  3 * Copyright (c) Microsoft Corporation. 
  4 *
  5 * This source code is subject to terms and conditions of the Microsoft Public License. A 
  6 * copy of the license can be found in the License.html file at the root of this distribution. If 
  7 * you cannot locate the  Microsoft Public License, please send an email to 
  8 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
  9 * by the terms of the Microsoft Public License.
 10 *
 11 * You must not remove this notice, or any other, from this software.
 12 *
 13 *
 14 * ***************************************************************************/
 15
 16#if CODEPLEX_40
 17using System;
 18#else
 19using System; using Microsoft;
 20#endif
 21using System.Collections.Generic;
 22#if CODEPLEX_40
 23using System.Linq.Expressions;
 24#else
 25using Microsoft.Linq.Expressions;
 26#endif
 27using System.Reflection;
 28using Microsoft.Scripting.Runtime;
 29using AstUtils = Microsoft.Scripting.Ast.Utils;
 30
 31namespace Microsoft.Scripting.Actions.Calls {
 32#if CODEPLEX_40
 33    using Ast = System.Linq.Expressions.Expression;
 34#else
 35    using Ast = Microsoft.Linq.Expressions.Expression;
 36#endif
 37
 38    /// <summary>
 39    /// Updates fields/properties of the returned value with unused keyword parameters.
 40    /// </summary>
 41    class KeywordConstructorReturnBuilder : ReturnBuilder {
 42        private readonly ReturnBuilder _builder;
 43        private readonly int _kwArgCount;
 44        private readonly int[] _indexesUsed;
 45        private readonly MemberInfo[] _membersSet;
 46        private readonly bool _privateBinding;
 47
 48        public KeywordConstructorReturnBuilder(ReturnBuilder builder, int kwArgCount, int[] indexesUsed, MemberInfo[] membersSet,
 49            bool privateBinding)
 50            : base(builder.ReturnType) {
 51            _builder = builder;
 52            _kwArgCount = kwArgCount;
 53            _indexesUsed = indexesUsed;
 54            _membersSet = membersSet;
 55            _privateBinding = privateBinding;
 56        }
 57
 58        internal override Expression ToExpression(ParameterBinder parameterBinder, IList<ArgBuilder> args, IList<Expression> parameters, Expression ret) {
 59            List<Expression> sets = new List<Expression>();
 60
 61            ParameterExpression tmp = parameterBinder.GetTemporary(ret.Type, "val");
 62            sets.Add(
 63                Ast.Assign(tmp, ret)
 64            );
 65
 66            for (int i = 0; i < _indexesUsed.Length; i++) {
 67                Expression value = parameters[parameters.Count - _kwArgCount + _indexesUsed[i]];
 68                switch(_membersSet[i].MemberType) {
 69                    case MemberTypes.Field:
 70                        FieldInfo fi = (FieldInfo)_membersSet[i];
 71                        if (!fi.IsLiteral && !fi.IsInitOnly) {
 72                            sets.Add(
 73                                Ast.Assign(
 74                                    Ast.Field(tmp, fi),
 75                                    ConvertToHelper(parameterBinder, value, fi.FieldType)
 76                                )
 77                            );
 78                        } else {
 79                            // call a helper which throws the error but "returns object"
 80                            sets.Add(
 81                                Ast.Convert(
 82                                    Ast.Call(
 83                                        typeof(ScriptingRuntimeHelpers).GetMethod("ReadOnlyAssignError"),
 84                                        AstUtils.Constant(true),
 85                                        AstUtils.Constant(fi.Name)
 86                                    ),
 87                                    fi.FieldType
 88                                )
 89                            );
 90                        }                        
 91                        break;
 92
 93                    case MemberTypes.Property:
 94                        PropertyInfo pi = (PropertyInfo)_membersSet[i];
 95                        if (pi.GetSetMethod(_privateBinding) != null) {
 96                            sets.Add(
 97                                Ast.Assign(
 98                                    Ast.Property(tmp, pi),
 99                                    ConvertToHelper(parameterBinder, value, pi.PropertyType)
100                                )
101                            );
102                        } else {
103                            // call a helper which throws the error but "returns object"
104                            sets.Add(
105                                Ast.Convert(
106                                    Ast.Call(
107                                        typeof(ScriptingRuntimeHelpers).GetMethod("ReadOnlyAssignError"),
108                                        AstUtils.Constant(false),
109                                        AstUtils.Constant(pi.Name)
110                                    ),
111                                    pi.PropertyType
112                                )
113                            );
114                        }
115                        break;
116                }
117            }
118
119            sets.Add(
120                tmp
121            );
122
123            Expression newCall = Ast.Block(
124                sets.ToArray()
125            );
126
127            return _builder.ToExpression(parameterBinder, args, parameters, newCall);
128        }
129
130        private static Expression ConvertToHelper(ParameterBinder parameterBinder, Expression value, Type type) {
131            if (type == value.Type) {
132                return value;
133            }
134
135            if (type.IsAssignableFrom(value.Type)) {
136                return AstUtils.Convert(value, type);
137            }
138
139            return parameterBinder.GetDynamicConversion(value, type);
140        }
141    }
142}