public JsExpression CompileToJavascript(DataContextStack dataContext, Expression expression)
        {
            var currentContextVariable = new JsTemporaryVariableParameter(new JsIdentifierExpression("ko").Member("contextFor").Invoke(new JsSymbolicParameter(CommandBindingExpression.SenderElementParameter)));
            var resultPromiseVariable  = new JsTemporaryVariableParameter(new JsNewExpression("DotvvmPromise"));
            var senderVariable         = new JsTemporaryVariableParameter(new JsSymbolicParameter(CommandBindingExpression.SenderElementParameter));
            var visitor      = new ExtractExpressionVisitor(ex => ex.NodeType == ExpressionType.Call && ex is MethodCallExpression methodCall && javascriptTranslator.TryTranslateMethodCall(methodCall.Object, methodCall.Arguments.ToArray(), methodCall.Method, dataContext) == null);
            var rootCallback = visitor.Visit(expression);
            var js           = SouldCompileCallback(rootCallback) ? new JsSymbolicParameter(resultPromiseVariable).Member("resolve").Invoke(javascriptTranslator.CompileToJavascript(rootCallback, dataContext)) : null;

            foreach (var param in visitor.ParameterOrder.Reverse <ParameterExpression>())
            {
                js = js ?? new JsSymbolicParameter(resultPromiseVariable).Member("resolve").Invoke(new JsIdentifierExpression(param.Name));
                var callback = new JsFunctionExpression(new[] { new JsIdentifier(param.Name) }, new JsBlockStatement(new JsExpressionStatement(js)));
                var method   = visitor.Replaced[param] as MethodCallExpression;
                js = CompileMethodCall(method, dataContext, callback);
            }
            foreach (var sp in js.Descendants.OfType <JsSymbolicParameter>())
            {
                if (sp.Symbol == JavascriptTranslator.KnockoutContextParameter)
                {
                    sp.Symbol = currentContextVariable;
                }
                else if (sp.Symbol == JavascriptTranslator.KnockoutViewModelParameter)
                {
                    sp.ReplaceWith(new JsSymbolicParameter(currentContextVariable).Member("$data"));
                }
                else if (sp.Symbol == CommandBindingExpression.SenderElementParameter)
                {
                    sp.Symbol = senderVariable;
                }
            }
            return(new JsBinaryExpression(js, BinaryOperatorType.Sequence, new JsSymbolicParameter(resultPromiseVariable)));
        }
        public JsExpression CompileToJavascript(DataContextStack dataContext, Expression expression)
        {
            var currentContextVariable = new JsTemporaryVariableParameter(new JsIdentifierExpression("ko").Member("contextFor").Invoke(new JsSymbolicParameter(CommandBindingExpression.SenderElementParameter)));
            // var resultPromiseVariable = new JsNewExpression("DotvvmPromise"));
            var senderVariable = new JsTemporaryVariableParameter(new JsSymbolicParameter(CommandBindingExpression.SenderElementParameter));
            var visitor        = new ExtractExpressionVisitor(ex => {
                if (ex.NodeType == ExpressionType.Call && ex is MethodCallExpression methodCall)
                {
                    if (javascriptTranslator.TryTranslateMethodCall(methodCall.Object, methodCall.Arguments.ToArray(), methodCall.Method, dataContext) is JsExpression jsTranslation)
                    {
                        if (jsTranslation.Annotation <ResultIsPromiseAnnotation>() is ResultIsPromiseAnnotation promiseAnnotation)
                        {
                            return(p => new BindingParameterAnnotation(extensionParameter: new JavascriptTranslationVisitor.FakeExtensionParameter(_ => new JsIdentifierExpression(p.Name).WithAnnotations(promiseAnnotation.ResultAnnotations), p.Name, new ResolvedTypeDescriptor(p.Type))));
                        }
                        else
                        {
                            return(null);
                        }
                    }
                    return(p => new BindingParameterAnnotation(extensionParameter: new JavascriptTranslationVisitor.FakeExtensionParameter(_ => new JsIdentifierExpression(p.Name).WithAnnotation(new ViewModelInfoAnnotation(p.Type)), p.Name, new ResolvedTypeDescriptor(p.Type))));
                }
                return(null);
            });
            var rootCallback = visitor.Visit(expression);
            var js           = SouldCompileCallback(rootCallback) ? new JsIdentifierExpression("resolve").Invoke(javascriptTranslator.CompileToJavascript(rootCallback, dataContext)) : null;

            foreach (var param in visitor.ParameterOrder.Reverse <ParameterExpression>())
            {
                js = js ?? new JsIdentifierExpression("resolve").Invoke(new JsIdentifierExpression(param.Name));
                var callback = new JsFunctionExpression(new[] { new JsIdentifier(param.Name) }, new JsBlockStatement(new JsExpressionStatement(js)));
                var method   = visitor.Replaced[param] as MethodCallExpression;
                js = CompileMethodCall(method, dataContext, callback);
            }
            foreach (var sp in js.Descendants.OfType <JsSymbolicParameter>())
            {
                if (sp.Symbol == JavascriptTranslator.KnockoutContextParameter)
                {
                    sp.Symbol = currentContextVariable;
                }
                else if (sp.Symbol == JavascriptTranslator.KnockoutViewModelParameter)
                {
                    sp.ReplaceWith(new JsSymbolicParameter(currentContextVariable).Member("$data"));
                }
                else if (sp.Symbol == CommandBindingExpression.SenderElementParameter)
                {
                    sp.Symbol = senderVariable;
                }
            }

            if (js is JsInvocationExpression invocation && invocation.Target is JsIdentifierExpression identifier && identifier.Identifier == "resolve")
            {
                // optimize `new Promise(function (resolve) { resolve(x) })` to `Promise.resolve(x)`
                identifier.ReplaceWith(new JsIdentifierExpression("Promise").Member("resolve"));
                return(js);
            }
Пример #3
0
        public JsExpression TryTranslateCall(LazyTranslatedExpression context, LazyTranslatedExpression[] arguments, MethodInfo method)
        {
            var tmp = new JsTemporaryVariableParameter();

            return(new JsBinaryExpression(
                       new JsAssignmentExpression(new JsSymbolicParameter(tmp), new JsInvocationExpression(new JsIdentifierExpression("dotvvm").Member("globalize").Member("parseDotvvmDate"), context.JsExpression())),
                       BinaryOperatorType.Sequence,
                       new JsNewExpression("Date",
                                           new JsInvocationExpression(new JsMemberAccessExpression(new JsSymbolicParameter(tmp), "getFullYear")),
                                           new JsInvocationExpression(new JsMemberAccessExpression(new JsSymbolicParameter(tmp), "getMonth")),
                                           new JsBinaryExpression(new JsInvocationExpression(new JsMemberAccessExpression(new JsSymbolicParameter(tmp), "getDate")), BinaryOperatorType.Plus, arguments[0].JsExpression()),
                                           new JsInvocationExpression(new JsMemberAccessExpression(new JsSymbolicParameter(tmp), "getHours")),
                                           new JsInvocationExpression(new JsMemberAccessExpression(new JsSymbolicParameter(tmp), "getMinutes")),
                                           new JsInvocationExpression(new JsMemberAccessExpression(new JsSymbolicParameter(tmp), "getSeconds")),
                                           new JsInvocationExpression(new JsMemberAccessExpression(new JsSymbolicParameter(tmp), "getMilliseconds"))
                                           )
                       ));
        }
        public override void VisitAssignmentExpression(JsAssignmentExpression assignmentExpression)
        {
            base.VisitAssignmentExpression(assignmentExpression);

            // change assignment to observable property to observable invocation
            // only do for RestultIsObservable, not ResultMayBeObservable
            if (assignmentExpression.Left.HasAnnotation <ResultIsObservableAnnotation>())
            {
                var value    = assignmentExpression.Right.Detach();
                var assignee = assignmentExpression.Left.Detach();
                assignee.RemoveAnnotations <ResultIsObservableAnnotation>();
                if (value.IsComplexType())
                {
                    assignmentExpression.ReplaceWith(_ => new JsIdentifierExpression("dotvvm").Member("serialization").Member("deserialize").Invoke(value, assignee));
                }
                else
                {
                    // A = B -> A(B)
                    assignee.RemoveAnnotations <MayBeNullAnnotation>();
                    JsExpression newExpression = new JsInvocationExpression(assignee, value)
                                                 .WithAnnotation(ObservableSetterInvocationAnnotation.Instance);
                    if (assignmentExpression.Parent is JsExpression resultConsumer)
                    {
                        // assignment's result
                        if (assignee is JsMemberAccessExpression memberAccess)
                        {
                            // x.A(B) -> x.A(B).A
                            newExpression = AddAnnotations(newExpression.Member(memberAccess.MemberName).Invoke().WithAnnotation(ObservableUnwrapInvocationAnnotation.Instance), value);
                        }
                        else
                        {
                            // f() = CC -> f()(_a = CC), _a
                            var tmp = new JsTemporaryVariableParameter();
                            value.ReplaceWith(_ => new JsAssignmentExpression(new JsSymbolicParameter(tmp), value));
                            newExpression = AddAnnotations(new JsBinaryExpression(newExpression, BinaryOperatorType.Sequence, new JsSymbolicParameter(tmp)), value);
                        }
                    }
                    assignmentExpression.ReplaceWith(newExpression);
                }
            }
        }