예제 #1
0
        internal static LambdaNode ParseAndBindLambda(IHostEnvironment env, string expression, int ivec, DataViewType[] inputTypes, out int[] perm)
        {
            perm = Utils.GetIdentityPermutation(inputTypes.Length);
            if (ivec >= 0)
            {
                if (ivec > 0)
                {
                    perm[0] = ivec;
                    for (int i = 1; i <= ivec; i++)
                    {
                        perm[i] = i - 1;
                    }
                }
            }
            CharCursor chars = new CharCursor(expression);

            var node = LambdaParser.Parse(out List <Error> errors, out List <int> lineMap, chars, perm, inputTypes);

            if (Utils.Size(errors) > 0)
            {
                throw env.ExceptParam(nameof(expression), $"parsing failed: {errors[0].GetMessage()}");
            }

            using (var ch = env.Start("LabmdaBinder.Run"))
                LambdaBinder.Run(env, ref errors, node, msg => ch.Error(msg));

            if (Utils.Size(errors) > 0)
            {
                throw env.ExceptParam(nameof(expression), $"binding failed: {errors[0].GetMessage()}");
            }
            return(node);
        }
예제 #2
0
        /// <summary>
        /// Binds specified syntax tree to concrete types and optional context.
        /// </summary>
        /// <param name="node">Syntax tree. Not null.</param>
        /// <param name="global">Context expression. Can be null. Usually <see cref="Expression.Constant(object)"/>.</param>
        /// <returns></returns>
        public LambdaExpression Bind(SyntaxTreeNode node, Expression global = null)
        {
            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            var bindingContext = default(BindingContext);

            // lambda binding substitution feature
            if (node.GetExpressionType(throwOnError: true) == Constants.EXPRESSION_TYPE_LAMBDA && this.resultType.IsDelegate == false)
            {
                var newParameterNames = LambdaBinder.ExtractArgumentNames(node);
                if (newParameterNames.Length != this.parameters.Count)
                {
                    throw new ExpressionParserException(Resources.EXCEPTION_BIND_UNABLEREMAPPARAMETERSCOUNTMISMATCH, node);
                }

                var newParameters = new ParameterExpression[newParameterNames.Length];
                for (var i = 0; i < newParameters.Length; i++)
                {
                    newParameters[i] = Expression.Parameter(this.parameters[i].Type, newParameterNames[i]);
                }
                bindingContext = new BindingContext(this.typeResolver, new ReadOnlyCollection <ParameterExpression>(newParameters), this.resultType, global);
                node           = node.GetExpression(throwOnError: true);
            }
            else
            {
                bindingContext = new BindingContext(this.typeResolver, this.parameters, this.resultType, global);
            }
            var body         = default(Expression);
            var bindingError = default(Exception);

            if (AnyBinder.TryBind(node, bindingContext, this.resultType, out body, out bindingError) == false)
            {
                throw bindingError;
            }

            Debug.Assert(body != null, "body != null");

            bindingContext.CompleteNullPropagation(ref body);

            if (body.Type != this.resultType && this.resultType.IsVoid == false)
            {
                try
                {
                    body = Expression.ConvertChecked(body, this.resultType);
                }
                catch (InvalidOperationException)
                {
                    throw new InvalidOperationException(string.Format(Resources.EXCEPTION_BIND_INVALIDLAMBDABODYTYPE, body.Type, this.resultType));
                }
            }

            return(Expression.Lambda(this.lambdaType, body, bindingContext.Parameters));
        }
예제 #3
0
        public void AnyTokenWithEntityCollectionParentConstantExpression()
        {
            var binder   = new LambdaBinder(this.FakeBindMethod);
            var state    = this.GetBindingStateForTest(HardCodedTestModel.GetPersonTypeReference(), HardCodedTestModel.GetPeopleSet());
            var anyToken = this.CreateTestAnyQueryToken();

            var result = binder.BindLambdaToken(anyToken, state);

            result.ShouldBeAnyQueryNode().And.Source.ShouldBeEntitySetQueryNode(HardCodedTestModel.GetPeopleSet());
            result.Body.ShouldBeConstantQueryNode(true);
        }
예제 #4
0
        public void BindLambdaTokenShouldPassForOpenPropertyParent()
        {
            this.parentQueryNode = new CollectionOpenPropertyAccessNode(new ConstantNode(null), "SomeCollectionProperty");
            var binder   = new LambdaBinder(this.FakeBindMethod);
            var state    = this.GetBindingStateForTest(HardCodedTestModel.GetPaintingTypeReference(), HardCodedTestModel.GetPaintingsSet());
            var allToken = this.CreateTestAllQueryToken();

            Action bind = () => binder.BindLambdaToken(allToken, state);

            bind.ShouldNotThrow();
        }
예제 #5
0
        public void BindLambdaTokenShouldFailForNonCollectionParent()
        {
            this.parentQueryNode = new ConstantNode(true);
            var binder   = new LambdaBinder(this.FakeBindMethod);
            var state    = this.GetBindingStateForTest(HardCodedTestModel.GetPersonTypeReference(), HardCodedTestModel.GetPeopleSet());
            var allToken = this.CreateTestAllQueryToken();

            Action bind = () => binder.BindLambdaToken(allToken, state);

            bind.Throws <ODataException>(Strings.MetadataBinder_LambdaParentMustBeCollection);
        }
예제 #6
0
        public void BindLambdaTokenShouldFailForNonBoolExpression()
        {
            this.expressionQueryNode = new ConstantNode(0);
            var binder   = new LambdaBinder(this.FakeBindMethod);
            var state    = this.GetBindingStateForTest(HardCodedTestModel.GetPersonTypeReference(), HardCodedTestModel.GetPeopleSet());
            var allToken = this.CreateTestAnyQueryToken();

            Action bind = () => binder.BindLambdaToken(allToken, state);

            bind.Throws <ODataException>(Strings.MetadataBinder_AnyAllExpressionNotSingleValue);
        }
예제 #7
0
        public void AllTokenWithNonEntityCollectionParentNonConstantExpression()
        {
            this.parentQueryNode     = new CollectionPropertyAccessNode(new ConstantNode(null), HardCodedTestModel.GetDogNicknamesProperty());
            this.expressionQueryNode = new BinaryOperatorNode(BinaryOperatorKind.LessThanOrEqual, new ConstantNode(1), new ConstantNode(5));
            var binder   = new LambdaBinder(this.FakeBindMethod);
            var state    = this.GetBindingStateForTest(HardCodedTestModel.GetPersonTypeReference(), HardCodedTestModel.GetPeopleSet());
            var allToken = this.CreateTestAllQueryToken();

            var result = binder.BindLambdaToken(allToken, state);

            result.ShouldBeAllQueryNode().And.Source.ShouldBeCollectionPropertyAccessQueryNode(HardCodedTestModel.GetDogNicknamesProperty());
            result.Body.ShouldBeBinaryOperatorNode(BinaryOperatorKind.LessThanOrEqual);
        }
예제 #8
0
        public void AnyTokenWithNonConstantExpressionNullParameter()
        {
            this.expressionQueryNode = new UnaryOperatorNode(UnaryOperatorKind.Negate, new ConstantNode(false));
            var binder     = new LambdaBinder(this.FakeBindMethod);
            var state      = this.GetBindingStateForTest(HardCodedTestModel.GetPersonTypeReference(), HardCodedTestModel.GetPeopleSet());
            var expression = new LiteralToken("foo");
            var parent     = new LiteralToken("bar");
            var anyToken   = new AnyToken(expression, null, parent);

            var result = binder.BindLambdaToken(anyToken, state);

            result.ShouldBeAnyQueryNode().And.Source.ShouldBeEntitySetQueryNode(HardCodedTestModel.GetPeopleSet());
            result.Body.ShouldBeUnaryOperatorNode(UnaryOperatorKind.Negate);
        }
        private void Run(string name)
        {
            string outDir = "ExprParser";

            string text         = GetResText(InResName(name));
            string inName       = name + "Input.txt";
            string outName      = name + "Output.txt";
            string outNameAssem = name + "Output.Assem.txt";
            string outPath      = DeleteOutputPath(outDir, outName);
            string outPathAssem = DeleteOutputPath(outDir, outNameAssem);

            using (var wr = OpenWriter(outPath))
            {
                var wrt = new IndentedTextWriter(wr, "  ");

                // Individual scripts are separated by $.
                // Inputs start after #.
                int count   = 0;
                int ichLim  = 0;
                int lineLim = 1;
                for (; ichLim < text.Length; ichLim++)
                {
                    int ichMin  = ichLim;
                    int lineMin = lineLim;

                    while (ichLim < text.Length && text[ichLim] != '$')
                    {
                        if (text[ichLim] == '\n')
                        {
                            lineLim++;
                        }
                        ichLim++;
                    }

                    while (ichMin < ichLim && char.IsWhiteSpace(text[ichMin]))
                    {
                        if (text[ichMin] == '\n')
                        {
                            lineMin++;
                        }
                        ichMin++;
                    }

                    if (ichMin >= ichLim)
                    {
                        continue;
                    }

                    // Process the script.
                    count++;
                    string scriptName = string.Format("Script {0}, lines {1} to {2}", count, lineMin, lineLim);
                    wrt.WriteLine("===== Start {0} =====", scriptName);
                    var types       = ParseTypes(text, ref ichMin, ichLim);
                    int ichLimChars = text.IndexOf('#', ichMin);
                    if (ichLimChars < 0 || ichLimChars >= ichLim)
                    {
                        ichLimChars = ichLim;
                    }
                    else
                    {
                        Contracts.Assert(ichMin < ichLimChars && ichLimChars < ichLim);
                    }
                    CharCursor chars = new CharCursor(text, ichMin, ichLimChars);
                    Delegate   del   = null;
                    lock (_sync)
                    {
                        try
                        {
                            LambdaNode   node;
                            List <Error> errors;
                            List <int>   lineMap;
                            var          perm = Utils.GetIdentityPermutation(types.Length);
                            using (wrt.Nest())
                            {
                                node = LambdaParser.Parse(out errors, out lineMap, chars, perm, types);
                            }
                            Check(node != null, "Null LambdaNode");
                            if (Utils.Size(errors) > 0)
                            {
                                DumpErrors(wrt, lineMap, lineMin, inName, "Parsing", errors);
                                goto LDone;
                            }

                            LambdaBinder.Run(Env, ref errors, node, msg => wr.WriteLine(msg));
                            if (Utils.Size(errors) > 0)
                            {
                                DumpErrors(wrt, lineMap, lineMin, inName, "Binding", errors);
                                goto LDone;
                            }
                            wrt.WriteLine("Binding succeeded. Output type: {0}", node.ResultType);

                            del = LambdaCompiler.Compile(out errors, node);
                            Contracts.Assert(TestFuncs1.Writer == null);
                            TestFuncs1.Writer = wr;
                            if (Utils.Size(errors) > 0)
                            {
                                DumpErrors(wrt, lineMap, lineMin, inName, "Compiling", errors);
                                goto LDone;
                            }

                            wrt.WriteLine("Compiling succeeded.");
                            if (ichLimChars < ichLim)
                            {
                                Evaluate(wrt, del, node.ResultType, types, text, ichLimChars + 1, ichLim);
                            }
                        }
                        catch (Exception ex)
                        {
                            if (!ex.IsMarked())
                            {
                                wrt.WriteLine("Unknown Exception: {0}!", del != null ? del.GetMethodInfo().DeclaringType : (object)"<null>");
                            }
                            wrt.WriteLine("Exception: {0}", ex.Message);
                        }
                        finally
                        {
                            TestFuncs1.Writer = null;
                        }

LDone:
                        wrt.WriteLine("===== End {0} =====", scriptName);
                    }
                }
            }

            CheckEquality(outDir, outName, digitsOfPrecision: 6);

            Done();
        }