Beispiel #1
0
        public override void ConvertToJavascript(JavascriptConversionContext context)
        {
            var initExpr = context.Node as MemberInitExpression;

            if (initExpr == null)
            {
                return;
            }
            var typeOk1 = this.NewObjectTypes?.Contains(initExpr.Type) ?? false;
            var typeOk2 = this.TypePredicate?.Invoke(initExpr.Type) ?? false;
            var typeOk3 = this.NewObjectTypes == null && this.TypePredicate == null;

            if (!typeOk1 && !typeOk2 && !typeOk3)
            {
                return;
            }
            if (initExpr.NewExpression.Arguments.Count > 0)
            {
                return;
            }
            if (initExpr.Bindings.Any(mb => mb.BindingType != MemberBindingType.Assignment))
            {
                return;
            }

            context.PreventDefault();
            var writer = context.GetWriter();

            using (writer.Operation(0))
            {
                writer.Write('{');

                var posStart = writer.Length;
                foreach (var assignExpr in initExpr.Bindings.Cast <MemberAssignment>())
                {
                    if (writer.Length > posStart)
                    {
                        writer.Write(',');
                    }

                    var metadataProvider = context.Options.GetMetadataProvider();
                    var meta             = metadataProvider.GetMemberMetadata(assignExpr.Member);
                    var memberName       = meta?.MemberName;
                    Debug.Assert(!string.IsNullOrEmpty(memberName), "!string.IsNullOrEmpty(memberName)");
                    if (Regex.IsMatch(memberName, @"^\w[\d\w]*$"))
                    {
                        writer.Write(memberName);
                    }
                    else
                    {
                        writer.WriteLiteral(memberName);
                    }

                    writer.Write(':');
                    context.Visitor.Visit(assignExpr.Expression);
                }

                writer.Write('}');
            }
        }
        public override void ConvertToJavascript(JavascriptConversionContext context)
        {
            var cte = context.Node as ConstantExpression;

            if (cte != null && cte.Type.GetTypeInfo().IsEnum)
            {
                context.PreventDefault();
                var  writer        = context.GetWriter();
                long remaining     = Convert.ToInt64(cte.Value);
                var  flagsAsString = (this.opts & EnumOptions.FlagsAsStringWithSeparator) != 0;
                var  flagsAsOrs    = (this.opts & EnumOptions.FlagsAsNumericOrs) != 0;
                var  flagsAsArray  = (this.opts & EnumOptions.FlagsAsArray) != 0;
                var  isFlags       = cte.Type.GetTypeInfo().IsDefined(typeof(FlagsAttribute), false);

                // when value is zero
                if (remaining == 0 && (!isFlags || !(flagsAsString || flagsAsOrs || flagsAsArray)))
                {
                    if (WriteSingleEnumItem(context, writer, 0, cte.Value, false))
                    {
                        return;
                    }
                }

                // reading enum composition
                var values   = Enum.GetValues(cte.Type);
                var selected = new List <int>();
                for (int itV = 0; itV < values.Length; itV++)
                {
                    var val = Convert.ToInt64(values.GetValue(values.Length - itV - 1));
                    if ((val & remaining) == val)
                    {
                        remaining &= ~val;
                        selected.Add(values.Length - itV - 1);

                        if (!isFlags)
                        {
                            break;
                        }
                    }
                }

                // selecting enum case
                if (isFlags)
                {
                    var cnt = selected.Count + (remaining != 0 ? 1 : 0);


                    PrecedenceController xpto = null;
                    string start     = "";
                    string separator = "";
                    string end       = "";

                    if (flagsAsString)
                    {
                        xpto      = writer.Operation(JavascriptOperationTypes.Literal);
                        start     = "\"";
                        separator = "|";
                        end       = "\"";
                    }
                    else if (flagsAsArray)
                    {
                        xpto      = writer.Operation(0);
                        start     = "[";
                        separator = ",";
                        end       = "]";
                    }
                    else if (flagsAsOrs && cnt > 1)
                    {
                        xpto      = writer.Operation(JavascriptOperationTypes.Or);
                        start     = "";
                        separator = "|";
                        end       = "";
                    }
                    else if (cnt > 1)
                    {
                        throw new NotSupportedException("When converting flags enums to JavaScript, a flags option must be specified.");
                    }

                    using (xpto)
                    {
                        writer.Write(start);
                        var pos0 = writer.Length;
                        for (int itIdx = 0; itIdx < selected.Count; itIdx++)
                        {
                            if (pos0 != writer.Length)
                            {
                                writer.Write(separator);
                            }

                            var index   = selected[itIdx];
                            var enumVal = values.GetValue(index);
                            var val     = Convert.ToInt64(enumVal);
                            WriteSingleEnumItem(context, writer, val, enumVal, flagsAsString);
                        }

                        if (remaining != 0)
                        {
                            if (pos0 != writer.Length)
                            {
                                writer.Write(separator);
                            }
                            WriteSingleEnumItem(context, writer, remaining, remaining, flagsAsString);
                        }
                        writer.Write(end);
                    }
                }
                else
                {
                    if (remaining != 0)
                    {
                        var enumVal = cte.Value;
                        var val     = Convert.ToInt64(cte.Value);
                        WriteSingleEnumItem(context, writer, val, enumVal, false);
                    }
                    else
                    {
                        foreach (var index in selected)
                        {
                            var enumVal = values.GetValue(index);
                            var val     = Convert.ToInt64(enumVal);
                            WriteSingleEnumItem(context, writer, val, enumVal, false);
                        }
                    }
                }
            }
        }
Beispiel #3
0
        public override void ConvertToJavascript(JavascriptConversionContext context)
        {
            var methodCall = context.Node as MethodCallExpression;

            if (methodCall != null)
            {
                if (methodCall.Method.DeclaringType == typeof(Enumerable))
                {
                    switch (methodCall.Method.Name)
                    {
                    case "Select":
                    {
                        context.PreventDefault();
                        var writer = context.GetWriter();
                        using (writer.Operation(JavascriptOperationTypes.Call))
                        {
                            using (writer.Operation(JavascriptOperationTypes.IndexerProperty))
                            {
                                // public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
                                // public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, TResult> selector)
                                var pars = methodCall.Method.GetParameters();
                                if (pars.Length != 2)
                                {
                                    throw new NotSupportedException("The `Enumerable.Select` method must have 2 parameters.");
                                }

                                context.Visitor.Visit(methodCall.Arguments[0]);
                                writer.Write(".map");
                            }

                            writer.Write('(');

                            // separator
                            using (writer.Operation(0))
                                context.Visitor.Visit(methodCall.Arguments[1]);

                            writer.Write(')');
                        }

                        return;
                    }

                    case "Where":
                    {
                        context.PreventDefault();
                        var writer = context.GetWriter();
                        using (writer.Operation(JavascriptOperationTypes.Call))
                        {
                            using (writer.Operation(JavascriptOperationTypes.IndexerProperty))
                            {
                                // public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
                                // public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, int, bool> predicate)
                                var pars = methodCall.Method.GetParameters();
                                if (pars.Length != 2)
                                {
                                    throw new NotSupportedException("The `Enumerable.Where` method must have 2 parameters.");
                                }

                                context.Visitor.Visit(methodCall.Arguments[0]);
                                writer.Write(".filter");
                            }

                            writer.Write('(');

                            // separator
                            using (writer.Operation(0))
                                context.Visitor.Visit(methodCall.Arguments[1]);

                            writer.Write(')');
                        }

                        return;
                    }

                    case "ToArray":
                    {
                        // Ecma Script 6+: use spread operator
                        // Other: use array `slice`
                        if (context.Options.ScriptVersion.Supports(JavascriptSyntaxFeature.ArraySpread))
                        {
                            context.PreventDefault();
                            var writer = context.GetWriter();
                            using (writer.Operation(0))
                            {
                                writer.Write('[');
                                writer.Write("...");
                                using (writer.Operation(JavascriptOperationTypes.ParamIsolatedLhs))
                                    context.Visitor.Visit(methodCall.Arguments[0]);
                                writer.Write(']');
                            }
                        }
                        else
                        {
                            context.PreventDefault();
                            var writer = context.GetWriter();
                            using (writer.Operation(JavascriptOperationTypes.Call))
                            {
                                using (writer.Operation(JavascriptOperationTypes.IndexerProperty))
                                {
                                    context.Visitor.Visit(methodCall.Arguments[0]);
                                    writer.Write(".slice");
                                }

                                writer.Write('(');
                                writer.Write(')');
                            }
                        }

                        return;
                    }
                    }
                }
            }
        }
Beispiel #4
0
        public override void ConvertToJavascript(JavascriptConversionContext context)
        {
            var methodCall = context.Node as MethodCallExpression;

            if (methodCall != null)
            {
                if (methodCall.Method.DeclaringType == typeof(string))
                {
                    switch (methodCall.Method.Name)
                    {
                    case "Concat":
                    {
                        context.PreventDefault();
                        var writer = context.GetWriter();
                        using (writer.Operation(JavascriptOperationTypes.Concat))
                        {
                            if (methodCall.Arguments.Count == 0)
                            {
                                writer.Write("''");
                            }
                            else
                            {
                                if (GetTypeOfExpression(methodCall.Arguments[0]) != typeof(string))
                                {
                                    writer.Write("''+");
                                }
                                context.WriteMany('+', methodCall.Arguments);
                            }
                        }

                        return;
                    }

                    case "Join":
                    {
                        context.PreventDefault();
                        var writer = context.GetWriter();
                        using (writer.Operation(JavascriptOperationTypes.Call))
                        {
                            using (writer.Operation(JavascriptOperationTypes.IndexerProperty))
                            {
                                var pars = methodCall.Method.GetParameters();
                                if (pars.Length == 4 && pars[1].ParameterType.IsArray && pars[2].ParameterType == typeof(int) && pars[3].ParameterType == typeof(int))
                                {
                                    throw new NotSupportedException("The `String.Join` method with start and count paramaters is not supported.");
                                }

                                if (pars.Length != 2 || !TypeHelpers.IsEnumerableType(pars[1].ParameterType))
                                {
                                    throw new NotSupportedException("This `String.Join` method is not supported.");
                                }

                                // if second parameter is an enumerable, render it directly
                                context.Visitor.Visit(methodCall.Arguments[1]);
                                writer.Write(".join");
                            }

                            writer.Write('(');

                            // separator
                            using (writer.Operation(0))
                                context.Visitor.Visit(methodCall.Arguments[0]);

                            writer.Write(')');
                        }

                        return;
                    }
                    }
                }
            }
        }
Beispiel #5
0
        public override void ConvertToJavascript(JavascriptConversionContext context)
        {
            var methodCall = context.Node as MethodCallExpression;

            if (methodCall != null)
            {
                if (methodCall.Method.DeclaringType == typeof(Math))
                {
                    NameLength jsInfo;
                    if (membersMap.TryGetValue(methodCall.Method.Name, out jsInfo))
                    {
                        if (methodCall.Arguments.Count == jsInfo.length)
                        {
                            context.PreventDefault();
                            using (context.Operation(JavascriptOperationTypes.Call))
                            {
                                using (context.Operation(JavascriptOperationTypes.IndexerProperty))
                                    context.Write("Math." + jsInfo.name);
                                context.WriteManyIsolated('(', ')', ',', methodCall.Arguments);
                            }

                            return;
                        }
                        else if (methodCall.Method.Name == "Log" &&
                                 methodCall.Arguments.Count == 2)
                        {
                            // JavaScript does not support `Math.log` with 2 parameters,
                            // But it is easy enough for us to give a little help!
                            context.PreventDefault();
                            using (context.Operation(JavascriptOperationTypes.MulDivMod))
                            {
                                using (context.Operation(JavascriptOperationTypes.Call))
                                {
                                    using (context.Operation(JavascriptOperationTypes.IndexerProperty))
                                        context.Write("Math.log");
                                    context.Write('(');
                                    using (context.Operation(0))
                                        context.Write(methodCall.Arguments[0]);
                                    context.Write(')');
                                }

                                context.Write('/');

                                using (context.Operation(JavascriptOperationTypes.Call))
                                {
                                    using (context.Operation(JavascriptOperationTypes.IndexerProperty))
                                        context.Write("Math.log");
                                    context.Write('(');
                                    using (context.Operation(0))
                                        context.Write(methodCall.Arguments[1]);
                                    context.Write(')');
                                }
                            }

                            return;
                        }
                        else if (methodCall.Method.Name == "Round" &&
                                 methodCall.Arguments.Count == 2 &&
                                 TypeHelpers.IsNumericType(methodCall.Arguments[1].Type))
                        {
                            // We won't support `Math.Round` with two parameters by default.
                            // To do it, we'd have to repeat an input value in the expression (unacceptable):
                            //      Math.Round(A, B) => Math.round(A * Math.pow(10, B)) / Math.pow(10, B)
                            // Or start helping with hacky things (acceptable, but not by default):
                            //      Math.Round(A, B) => (function(a, b) { return Math.round(a * b) / b; })(A, Math.pow(10, B));
                            if (this.round2)
                            {
                                context.PreventDefault();
                                using (context.Operation(JavascriptOperationTypes.Call))
                                {
                                    context.WriteLambda <Func <double, double, double> >((a, b) => Math.Round(a * b) / b);
                                    context.Write('(');
                                    using (context.Operation(0))
                                        context.Write(methodCall.Arguments[0]);
                                    context.Write(',');
                                    using (context.Operation(0))
                                        using (context.Operation(JavascriptOperationTypes.Call))
                                        {
                                            using (context.Operation(JavascriptOperationTypes.IndexerProperty))
                                                context.Write("Math.pow");
                                            context.Write('(');
                                            context.Write("10");
                                            context.Write(',');
                                            using (context.Operation(0))
                                                context.Write(methodCall.Arguments[1]);
                                            context.Write(')');
                                        }

                                    context.Write(')');

                                    return;
                                }
                            }
                        }
                    }
                }
            }

            // E and PI are constant values, they will never result in
            // a member access expression. We will have to catch the
            // exact numbers, and convert them instead.
            var constVal = context.Node as ConstantExpression;

            if (constVal != null)
            {
                if (constVal.Value.Equals(Math.E))
                {
                    context.PreventDefault();
                    using (context.Operation(JavascriptOperationTypes.IndexerProperty))
                        context.Write("Math.E");
                }
                else if (constVal.Value.Equals(Math.PI))
                {
                    context.PreventDefault();
                    using (context.Operation(JavascriptOperationTypes.IndexerProperty))
                        context.Write("Math.PI");
                }
            }
        }