Example #1
0
 /// <summary>
 /// Writes a literal value to the output.
 /// </summary>
 /// <param name="value">Value to write.</param>
 /// <returns>The <see cref="JavascriptWriter"/>, allowing a fluent style.</returns>
 public JavascriptWriter WriteLiteral(object value)
 {
     if (value is string || value is char)
     {
         this.result.Append('"');
         this.result.Append(value.ToString()
                            .Replace("\\", "\\\\")
                            .Replace("\r", "\\r")
                            .Replace("\n", "\\n")
                            .Replace("\t", "\\t")
                            .Replace("\0", "\\0")
                            .Replace("\"", "\\\""));
         this.result.Append('"');
     }
     else if (TypeHelpers.IsNumericType(value.GetType()))
     {
         if (TypeHelpers.IsIntegerType(value.GetType()))
         {
             this.result.Append(value);
         }
         else if (value is float || value is double || value is decimal)
         {
             this.result.AppendFormat("{0:E}", value);
         }
     }
     return(this);
 }
Example #2
0
        protected override Expression VisitConstant(ConstantExpression node)
        {
            if (TypeHelpers.IsNumericType(node.Type))
            {
                using (this.result.Operation(JavascriptOperationTypes.Literal))
                    this.result.Write(Convert.ToString(node.Value, CultureInfo.InvariantCulture));
            }
            else if (node.Type == typeof(string))
            {
                using (this.result.Operation(JavascriptOperationTypes.Literal))
                    this.WriteStringLiteral((string)node.Value);
            }
            else if (node.Type == typeof(Regex))
            {
                using (this.result.Operation(JavascriptOperationTypes.Literal))
                {
                    this.result.Write('/');
                    this.result.Write(node.Value);
                    this.result.Write("/g");
                }
            }
            else if (node.Value == null)
            {
                this.result.Write("null");
            }

            return(node);
        }
 /// <summary>
 /// Writes a literal value to the output.
 /// </summary>
 /// <param name="value">Value to write.</param>
 /// <returns>The <see cref="JavascriptWriter"/>, allowing a fluent style.</returns>
 public JavascriptWriter WriteLiteral(object value)
 {
     if (value is string || value is char)
     {
         this.result.Append('"');
         this.WriteLiteralStringContent(value);
         this.result.Append('"');
     }
     else if (TypeHelpers.IsNumericType(value.GetType()))
     {
         if (TypeHelpers.IsIntegerType(value.GetType()))
         {
             this.result.Append(value);
         }
         else if (value is float || value is double || value is decimal)
         {
             this.result.AppendFormat("{0:E}", value);
         }
     }
     return(this);
 }
Example #4
0
        public static void WriteOperator(StringBuilder result, ExpressionType nodeType, Type type)
        {
            switch (nodeType)
            {
            case ExpressionType.Add:
            case ExpressionType.AddChecked:
                result.Append('+');
                break;

            case ExpressionType.AddAssign:
            case ExpressionType.AddAssignChecked:
                result.Append("+=");
                break;

            case ExpressionType.And:
                result.Append("&");
                break;

            case ExpressionType.AndAlso:
                result.Append("&&");
                break;

            case ExpressionType.AndAssign:
                result.Append("&=");
                break;

            case ExpressionType.ArrayIndex:
                break;

            case ExpressionType.ArrayLength:
                result.Append(".length");
                break;

            case ExpressionType.Assign:
                result.Append("=");
                break;

            case ExpressionType.Block:
                break;

            case ExpressionType.Call:
                break;

            case ExpressionType.Coalesce:
                break;

            case ExpressionType.Conditional:
                break;

            case ExpressionType.Constant:
                break;

            case ExpressionType.Convert:
                break;

            case ExpressionType.ConvertChecked:
                break;

            case ExpressionType.DebugInfo:
                break;

            case ExpressionType.Decrement:
                result.Append("--");
                break;

            case ExpressionType.Default:
                break;

            case ExpressionType.Divide:
                result.Append("/");
                break;

            case ExpressionType.DivideAssign:
                result.Append("/=");
                break;

            case ExpressionType.Dynamic:
                break;

            case ExpressionType.Equal:
                result.Append("===");
                break;

            case ExpressionType.ExclusiveOr:
                result.Append("^");
                break;

            case ExpressionType.ExclusiveOrAssign:
                result.Append("^=");
                break;

            case ExpressionType.Extension:
                break;

            case ExpressionType.Goto:
                break;

            case ExpressionType.GreaterThan:
                result.Append(">");
                break;

            case ExpressionType.GreaterThanOrEqual:
                result.Append(">=");
                break;

            case ExpressionType.Increment:
                result.Append("++");
                break;

            case ExpressionType.Index:
                break;

            case ExpressionType.Invoke:
                break;

            case ExpressionType.IsFalse:
                break;

            case ExpressionType.IsTrue:
                break;

            case ExpressionType.Label:
                break;

            case ExpressionType.Lambda:
                break;

            case ExpressionType.LeftShift:
                result.Append("<<");
                break;

            case ExpressionType.LeftShiftAssign:
                result.Append("<<=");
                break;

            case ExpressionType.LessThan:
                result.Append("<");
                break;

            case ExpressionType.LessThanOrEqual:
                result.Append("<=");
                break;

            case ExpressionType.ListInit:
                break;

            case ExpressionType.Loop:
                break;

            case ExpressionType.MemberAccess:
                break;

            case ExpressionType.MemberInit:
                break;

            case ExpressionType.Modulo:
                result.Append("%");
                break;

            case ExpressionType.ModuloAssign:
                result.Append("%=");
                break;

            case ExpressionType.Multiply:
                result.Append("*");
                break;

            case ExpressionType.MultiplyAssign:
                result.Append("*=");
                break;

            case ExpressionType.MultiplyAssignChecked:
                break;

            case ExpressionType.MultiplyChecked:
                break;

            case ExpressionType.Negate:
            case ExpressionType.NegateChecked:
                result.Append("-");
                break;

            case ExpressionType.New:
                result.Append("new");
                break;

            case ExpressionType.NewArrayBounds:
                break;

            case ExpressionType.NewArrayInit:
                break;

            case ExpressionType.Not:
                if (TypeHelpers.IsNumericType(type) || type.GetTypeInfo().IsEnum)
                {
                    result.Append("~");
                }
                else
                {
                    result.Append("!");
                }

                break;

            case ExpressionType.NotEqual:
                result.Append("!==");
                break;

            case ExpressionType.OnesComplement:
                result.Append("~");
                break;

            case ExpressionType.Or:
                result.Append("|");
                break;

            case ExpressionType.OrAssign:
                result.Append("|=");
                break;

            case ExpressionType.OrElse:
                result.Append("||");
                break;

            case ExpressionType.Parameter:
                break;

            case ExpressionType.Power:
                break;

            case ExpressionType.PowerAssign:
                break;

            case ExpressionType.PostDecrementAssign:
            case ExpressionType.PreDecrementAssign:
                result.Append("--");
                break;

            case ExpressionType.PostIncrementAssign:
            case ExpressionType.PreIncrementAssign:
                result.Append("++");
                break;

            case ExpressionType.Quote:
                break;

            case ExpressionType.RightShift:
                result.Append(">>");
                break;

            case ExpressionType.RightShiftAssign:
                result.Append(">>=");
                break;

            case ExpressionType.RuntimeVariables:
                break;

            case ExpressionType.Subtract:
                result.Append("-");
                break;

            case ExpressionType.SubtractAssign:
                result.Append("-=");
                break;

            case ExpressionType.SubtractAssignChecked:
                result.Append("--");
                break;

            case ExpressionType.SubtractChecked:
                result.Append("-");
                break;

            case ExpressionType.Switch:
                break;

            case ExpressionType.Throw:
                break;

            case ExpressionType.Try:
                break;

            case ExpressionType.TypeAs:
                break;

            case ExpressionType.TypeEqual:
                break;

            case ExpressionType.TypeIs:
                break;

            case ExpressionType.UnaryPlus:
                break;

            case ExpressionType.Unbox:
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
Example #5
0
        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            if (node.Method.IsSpecialName)
            {
                var isIndexer = node.Method.Name == "get_Item" || node.Method.Name == "get_Chars";
                if (isIndexer)
                {
                    using (this.result.Operation(JavascriptOperationTypes.IndexerProperty))
                    {
                        this.Visit(node.Object);
                        this.result.Write('[');

                        using (this.result.Operation(0))
                        {
                            var posStart0 = this.result.Length;
                            foreach (var arg in node.Arguments)
                            {
                                if (this.result.Length != posStart0)
                                {
                                    this.result.Write(',');
                                }

                                this.Visit(arg);
                            }
                        }

                        this.result.Write(']');
                        return(node);
                    }
                }

                if (node.Method.Name == "set_Item")
                {
                    using (this.result.Operation(0))
                    {
                        using (this.result.Operation(JavascriptOperationTypes.AssignRhs))
                        {
                            using (this.result.Operation(JavascriptOperationTypes.IndexerProperty))
                            {
                                this.Visit(node.Object);
                                this.result.Write('[');

                                using (this.result.Operation(0))
                                {
                                    var posStart0 = this.result.Length;
                                    foreach (var arg in node.Arguments)
                                    {
                                        if (this.result.Length != posStart0)
                                        {
                                            this.result.Write(',');
                                        }

                                        this.Visit(arg);
                                    }
                                }

                                this.result.Write(']');
                            }
                        }

                        this.result.Write('=');
                        this.Visit(node.Arguments.Single());
                    }

                    return(node);
                }
            }
            else
            {
                if (node.Method.DeclaringType != null &&
                    (node.Method.Name == "ContainsKey" &&
                     TypeHelpers.IsDictionaryType(node.Method.DeclaringType)))
                {
                    using (this.result.Operation(JavascriptOperationTypes.Call))
                    {
                        using (this.result.Operation(JavascriptOperationTypes.IndexerProperty))
                            this.Visit(node.Object);
                        this.result.Write(".hasOwnProperty(");
                        using (this.result.Operation(0))
                            this.Visit(node.Arguments.Single());
                        this.result.Write(')');
                        return(node);
                    }
                }
            }

            if (node.Method.DeclaringType == typeof(string))
            {
                if (node.Method.Name == "Contains")
                {
                    using (this.result.Operation(JavascriptOperationTypes.Comparison))
                    {
                        using (this.result.Operation(JavascriptOperationTypes.Call))
                        {
                            using (this.result.Operation(JavascriptOperationTypes.IndexerProperty))
                                this.Visit(node.Object);
                            this.result.Write(".indexOf(");
                            using (this.result.Operation(0))
                            {
                                var posStart = this.result.Length;
                                foreach (var arg in node.Arguments)
                                {
                                    if (this.result.Length > posStart)
                                    {
                                        this.result.Write(',');
                                    }
                                    this.Visit(arg);
                                }
                            }

                            this.result.Write(')');
                        }

                        this.result.Write(">=0");
                        return(node);
                    }
                }
            }

            if (node.Method.Name == "ToString" && node.Type == typeof(string) && node.Object != null)
            {
                string methodName = null;
                if (node.Arguments.Count == 0 || typeof(IFormatProvider).IsAssignableFrom(node.Arguments[0].Type))
                {
                    methodName = "toString()";
                }
                else if (TypeHelpers.IsNumericType(node.Object.Type) &&
                         node.Arguments.Count >= 1 &&
                         node.Arguments[0].Type == typeof(string) &&
                         node.Arguments[0].NodeType == ExpressionType.Constant)
                {
                    var str   = (string)((ConstantExpression)node.Arguments[0]).Value;
                    var match = Regex.Match(str, @"^([DEFGNX])(\d*)$", RegexOptions.IgnoreCase);
                    var f     = match.Groups[1].Value.ToUpper();
                    var n     = match.Groups[2].Value;
                    if (f == "D")
                    {
                        methodName = "toString()";
                    }
                    else if (f == "E")
                    {
                        methodName = "toExponential(" + n + ")";
                    }
                    else if (f == "F" || f == "G")
                    {
                        methodName = "toFixed(" + n + ")";
                    }
                    else if (f == "N")
                    {
                        methodName = "toLocaleString()";
                    }
                    else if (f == "X")
                    {
                        methodName = "toString(16)";
                    }
                }

                if (methodName != null)
                {
                    using (this.result.Operation(JavascriptOperationTypes.Call))
                    {
                        using (this.result.Operation(JavascriptOperationTypes.IndexerProperty))
                            this.Visit(node.Object);
                        this.result.WriteFormat(".{0}", methodName);
                        return(node);
                    }
                }
            }

            if (!node.Method.IsStatic)
            {
                throw new NotSupportedException(string.Format("By default, Lambda2Js cannot convert custom instance methods, only static ones. `{0}` is not static.", node.Method.Name));
            }

            using (this.result.Operation(JavascriptOperationTypes.Call))
                if (node.Method.DeclaringType != null)
                {
                    this.result.Write(node.Method.DeclaringType.FullName);
                    this.result.Write('.');
                    this.result.Write(node.Method.Name);
                    this.result.Write('(');

                    var posStart = this.result.Length;
                    using (this.result.Operation(0))
                        foreach (var arg in node.Arguments)
                        {
                            if (this.result.Length != posStart)
                            {
                                this.result.Write(',');
                            }

                            this.Visit(arg);
                        }

                    this.result.Write(')');

                    return(node);
                }

            return(node);
        }
Example #6
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)
                        {
                            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!
                            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)
                            {
                                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))
                {
                    using (context.Operation(JavascriptOperationTypes.IndexerProperty))
                        context.Write("Math.E");
                }
                else if (constVal.Value.Equals(Math.PI))
                {
                    using (context.Operation(JavascriptOperationTypes.IndexerProperty))
                        context.Write("Math.PI");
                }
            }
        }