Esempio n. 1
0
        private string СompileSimpleExpression(string blankElectionId, string expr, int num)
        {
            var result = new StringBuilder(1024);

            result.Append(String.Format("private static int Expression{0}()", num));
            result.Append("{");
            result.Append("int result;");
            result.Append("VoteKey mask = new VoteKey();");
            var    parseResult  = new ParsedExpression(expr);
            bool   allElections = expr.Trim().StartsWith("{@");
            string blankId      = string.Empty;

            if (!allElections)
            {
                blankId = blankElectionId;
            }
            switch (parseResult.Type)
            {
            case ParsedExpression.ExpType.VotesSum:
                result.Append(String.Format(
                                  "mask.ElectionId = \"{0}\";",
                                  _template.ElectionLink.ElectionId));
                result.Append("result = Managers.VotingResultManager.VotingResults.VotesCount(mask);");
                break;

            case ParsedExpression.ExpType.MandateCount:
                result.Append("result = " + _template.ElectionLink.MaxMarks + ";");
                break;

            case ParsedExpression.ExpType.AgainstVotesCount:
                if (!_template.ElectionLink.NoneAboveExists)
                {
                    result.Append("result = 0");
                }
                else
                {
                    result.Append(String.Format(
                                      "mask.ElectionId = \"{0}\"; mask.CandidateId = \"{1}\";"
                                      , _template.ElectionLink.ElectionId
                                      , _template.ElectionLink.NoneAboveCandidate.Id));
                    result.Append("result = Managers.VotingResultManager.VotingResults.VotesCount(mask);");
                }
                break;

            case ParsedExpression.ExpType.RestrictedCount:
                if (0 != blankId.CompareTo(string.Empty))
                {
                    result.Append(String.Format("mask.BlankId = \"{0}\";", blankId));
                }
                PrepareMask(result, parseResult.Restrictions);
                result.Append("result = Managers.VotingResultManager.VotingResults.VotesCount(mask);");
                break;

            default:
                throw new Exception("Неизвестный тип выражения.");
            }
            result.Append("return result;");
            result.Append("}");
            return(result.ToString());
        }
Esempio n. 2
0
        public void InsertAdditionalParametersInParenthesizedBlock()
        {
            string expressionText = @"(string item,
// Not used:
int other
/*commented-out DateTime start*/) => {

/*start tag*/
return	item . Name;
/*end tag*/

}";

            var parsedExpression = new ParsedExpression(expressionText, new[] { "SomeType", "int" }, new TestConcept {
                Name = "Test"
            }, null, "1\r\n2");

            Assert.AreEqual(@"(string item,
// Not used:
int other1
2)
        {
            /*start tag*/
return	item . Name;
/*end tag*/
        }", parsedExpression.MethodParametersAndBody);
        }
Esempio n. 3
0
        public void CorrectValue(string input, double value)
        {
            StringExpression parser = new StringExpression(input, new TokenFactory());
            var parsed    = parser.Parse();
            var evaluator = new ParsedExpression(parsed);

            Assert.Equal(value, evaluator.Evaluate());
        }
Esempio n. 4
0
        public void DivisionByZero(string input)
        {
            StringExpression parser = new StringExpression(input, new TokenFactory());
            var parsed    = parser.Parse();
            var evaluator = new ParsedExpression(parsed);

            Assert.Throws <ArithmeticException>(() => evaluator.Evaluate());
        }
Esempio n. 5
0
        Expression IExpressionSerializer <TModel> .Deserialize(ParsedExpression parsedExpression)
        {
            if (parsedExpression == null)
            {
                throw new ArgumentNullException(nameof(parsedExpression));
            }

            return(Deserialize(parsedExpression));
        }
 public ParsedCatchBlock(
     ParsedType type,
     ParsedParameterExpression variable,
     ParsedExpression filter,
     ParsedExpression body)
 {
     this.Type     = type;
     this.Variable = variable;
     this.Filter   = filter;
     this.Body     = body;
 }
Esempio n. 7
0
        public void ExpressionsParameters()
        {
            // Input format: "Expression / ArgumentTypes"
            string tests =
                @"
a => a.Length
(a, b) => a.Length
(a, b) => (a + b).Length / List<C> double
(string a, List<C> b) => (a + b).Length / List<C> double
(string a, List<C> b) => (a + b).Length
(string a, b) => (a + b).Length / int double
";
            string expected = // Format: MethodParameters / MethodBody / ResultLiteral(if available), or Exception.
                              @"
null-a
null-a, null-b
List<C>-a, double-b
string-a, List<C>-b
string-a, List<C>-b
int-a, double-b
";

            IConceptInfo testConcept = new TestConcept {
                Name = "Test"
            };

            var results = new List <string>();

            foreach (var test in tests.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries))
            {
                var      testParts      = test.Split('/');
                string   expressionText = testParts[0].Trim();
                string[] argumentTypes  = testParts.Length > 1
                    ? testParts[1].Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(argument => argument.Trim()).ToArray()
                    : null;

                try
                {
                    var parsedExpression = new ParsedExpression(expressionText, argumentTypes, testConcept);
                    results.Add(TestUtility.Dump(parsedExpression.ExpressionParameters, p => $"{p.Type ?? "null"}-{p.Name}"));
                }
                catch (Exception e)
                {
                    results.Add($"{e.GetType().Name}: {e.Message}");
                }
            }

            string report = string.Join("\r\n", results);

            Console.WriteLine(report.Replace("\"", "\"\""));

            TestUtility.AssertAreEqualByLine(expected.Trim(), report);
        }
Esempio n. 8
0
        public void InsertAdditionalCodeInBlock2()
        {
            string expressionText = @"item => { return item.Name; }";

            var parsedExpression = new ParsedExpression(expressionText, new[] { "SomeType" }, new TestConcept {
                Name = "Test"
            }, "/*InsertedCode*/");

            Assert.AreEqual(@"(SomeType item)
        {/*InsertedCode*/
            return item.Name;
        }", parsedExpression.MethodParametersAndBody);
        }
Esempio n. 9
0
        public void FormattingSimpleLambdaWithLineComment()
        {
            string expressionText = @"item => item.Name // Comment. \t \t";

            var parsedExpression = new ParsedExpression(expressionText, new[] { "SomeType" }, new TestConcept {
                Name = "Test"
            });

            // The line-comment must not invalidate the semicolon!
            Assert.AreEqual(@"(SomeType item)
        {
            return item.Name;
        }", parsedExpression.MethodParametersAndBody);
        }
Esempio n. 10
0
        public void InsertAdditionalCodeInSimpleLambda()
        {
            string expressionText = @"item => item . Name+
item.Surname";

            var parsedExpression = new ParsedExpression(expressionText, new[] { "SomeType" }, new TestConcept {
                Name = "Test"
            }, "/*InsertedCode*/");

            // Place the block under the parameters line to match standard method formatting.
            Assert.AreEqual(@"(SomeType item)
        {/*InsertedCode*/
            return item . Name+
item.Surname;
        }", parsedExpression.MethodParametersAndBody);
        }
Esempio n. 11
0
        public void Run <TResult>(IQueryable <Model> models, Expression <Func <Model, TResult> > source)
        {
            if (models == null)
            {
                throw new ArgumentNullException(nameof(models));
            }
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            try
            {
                string json = null;
                Expression <Func <Model, TResult> > destination = null;

                try
                {
                    ParsedExpression serialized = this._expressionSerializer.Serialize(source);
                    json = JsonConvert.SerializeObject(serialized, __jsonSerializerSettings);

                    ParsedExpression deserialized = JsonConvert.DeserializeObject <ParsedExpression>(json, __jsonSerializerSettings);
                    destination = (Expression <Func <Model, TResult> >) this._expressionSerializer.Deserialize(deserialized);
                }
                finally
                {
                    this._logger.LogInformation($"{nameof(source)}:\t\t{source}");
                    if (destination != null)
                    {
                        this._logger.LogInformation($"{nameof(destination)}:\t{destination}");
                    }
                    this._logger.LogInformation($"{nameof(json)}:\r\n{json ?? string.Empty}");
                }

                this._logger.LogInformation($"{nameof(source)}:\t\t{JsonConvert.SerializeObject(models.Select(source).ToArray())}");
                this._logger.LogInformation($"{nameof(destination)}:\t{JsonConvert.SerializeObject(models.Select(destination).ToArray())}");
            }
            catch (Exception ex)
            {
                this._logger.LogError(ex.ToString());
            }
        }
Esempio n. 12
0
 private void btnParse_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
 {
     #region #parse
     FormulaEngine engine = spreadsheetControl1.Document.FormulaEngine;
     if (spreadsheetControl1.ActiveCell != null)
     {
         // Get the formula for parsing.
         string formula = spreadsheetControl1.ActiveCell.Formula;
         if (formula != string.Empty)
         {
             // Parse the formula
             ParsedExpression p_expr = engine.Parse(formula);
             // Traverse the expression tree and modify it.
             MyVisitor visitor = new MyVisitor();
             p_expr.Expression.Visit(visitor);
             // Reconsitute the formula.
             string formula1 = p_expr.ToString();
             // Place the formula back to the cell.
             spreadsheetControl1.ActiveCell.Formula = formula1;
         }
         #endregion #parse
     }
 }
Esempio n. 13
0
        public void FormattingSimpleLambda()
        {
            string expressionText = @"
item
 => //1
/*2*/
item . Name+
item.Surname
/*3*/";

            var parsedExpression = new ParsedExpression(expressionText, new[] { "SomeType" }, new TestConcept {
                Name = "Test"
            });

            // Place the block under the parameters line to match standard method formatting.
            Assert.AreEqual(@"(SomeType item)
        {
            return //1
/*2*/
item . Name+
item.Surname;
        }", parsedExpression.MethodParametersAndBody);
        }
Esempio n. 14
0
        public void FormattingBlock()
        {
            string expressionText = @"(string item,
// Not used:
int other
/*commented-out DateTime start*/)
=> {
return	item . Name;

}";

            var parsedExpression = new ParsedExpression(expressionText, new[] { "SomeType", "int" }, new TestConcept {
                Name = "Test"
            });

            // Keep the original formatting withing the block. Place the block under the parameters line to match formatting of the other expression types.
            Assert.AreEqual(@"(string item,
// Not used:
int other)
        {
            return	item . Name;
        }", parsedExpression.MethodParametersAndBody);
        }
Esempio n. 15
0
 public Expression <Func <TModel, TResult> > Deserialize <TResult>(ParsedExpression parsedExpression)
 {
     return((Expression <Func <TModel, TResult> >)Deserialize(parsedExpression));
 }
        public Expression Deserialize(ParsedExpression parsedExpression)
        {
            if (parsedExpression == null)
            {
                throw new ArgumentNullException(nameof(parsedExpression));
            }

            switch (parsedExpression.NodeType)
            {
            case ExpressionType.Block:
                return(Deserialize(parsedExpression as ParsedBlockExpression));

            case ExpressionType.Call:
                return(Deserialize(parsedExpression as ParsedMethodCallExpression));

            case ExpressionType.Constant:
                return(Deserialize(parsedExpression as ParsedConstantExpression));

            case ExpressionType.Conditional:
                return(Deserialize(parsedExpression as ParsedConditionalExpression));

            case ExpressionType.DebugInfo:
                return(Deserialize(parsedExpression as ParsedDebugInfoExpression));

            case ExpressionType.Default:
                return(Deserialize(parsedExpression as ParsedDefaultExpression));

            case ExpressionType.Dynamic:
                return(Deserialize(parsedExpression as ParsedDynamicExpression));

            case ExpressionType.Goto:
                return(Deserialize(parsedExpression as ParsedGotoExpression));

            case ExpressionType.Index:
                return(Deserialize(parsedExpression as ParsedIndexExpression));

            case ExpressionType.Invoke:
                return(Deserialize(parsedExpression as ParsedInvocationExpression));

            case ExpressionType.Label:
                return(Deserialize(parsedExpression as ParsedLabelExpression));

            case ExpressionType.Lambda:
                return(Deserialize(parsedExpression as ParsedLambdaExpression));

            case ExpressionType.ListInit:
                return(Deserialize(parsedExpression as ParsedListInitExpression));

            case ExpressionType.Loop:
                return(Deserialize(parsedExpression as ParsedLoopExpression));

            case ExpressionType.MemberAccess:
                return(Deserialize(parsedExpression as ParsedMemberExpression));

            case ExpressionType.MemberInit:
                return(Deserialize(parsedExpression as ParsedMemberInitExpression));

            case ExpressionType.New:
                return(Deserialize(parsedExpression as ParsedNewExpression));

            case ExpressionType.Parameter:
                return(Deserialize(parsedExpression as ParsedParameterExpression));

            case ExpressionType.RuntimeVariables:
                return(Deserialize(parsedExpression as ParsedRuntimeVariablesExpression));

            case ExpressionType.Switch:
                return(Deserialize(parsedExpression as ParsedSwitchExpression));

            case ExpressionType.Try:
                return(Deserialize(parsedExpression as ParsedTryExpression));

            case ExpressionType.TypeEqual:
                return(Deserialize(parsedExpression as ParsedTypeBinaryExpression));

            case ExpressionType.NewArrayBounds:
            case ExpressionType.NewArrayInit:
                return(Deserialize(parsedExpression as ParsedNewArrayExpression));

            case ExpressionType.Add:
            case ExpressionType.AddAssign:
            case ExpressionType.AddChecked:
            case ExpressionType.AddAssignChecked:
            case ExpressionType.And:
            case ExpressionType.AndAlso:
            case ExpressionType.AndAssign:
            case ExpressionType.ArrayIndex:
            case ExpressionType.Assign:
            case ExpressionType.Coalesce:
            case ExpressionType.Divide:
            case ExpressionType.DivideAssign:
            case ExpressionType.Equal:
            case ExpressionType.ExclusiveOr:
            case ExpressionType.ExclusiveOrAssign:
            case ExpressionType.GreaterThan:
            case ExpressionType.GreaterThanOrEqual:
            case ExpressionType.LeftShift:
            case ExpressionType.LeftShiftAssign:
            case ExpressionType.LessThan:
            case ExpressionType.LessThanOrEqual:
            case ExpressionType.Modulo:
            case ExpressionType.ModuloAssign:
            case ExpressionType.Multiply:
            case ExpressionType.MultiplyAssign:
            case ExpressionType.MultiplyChecked:
            case ExpressionType.MultiplyAssignChecked:
            case ExpressionType.NotEqual:
            case ExpressionType.Or:
            case ExpressionType.OrAssign:
            case ExpressionType.OrElse:
            case ExpressionType.Power:
            case ExpressionType.PowerAssign:
            case ExpressionType.RightShift:
            case ExpressionType.RightShiftAssign:
            case ExpressionType.Subtract:
            case ExpressionType.SubtractAssign:
            case ExpressionType.SubtractChecked:
            case ExpressionType.SubtractAssignChecked:
            case ExpressionType.TypeIs:
                return(Deserialize(parsedExpression as ParsedBinaryExpression));

            case ExpressionType.ArrayLength:
            case ExpressionType.Convert:
            case ExpressionType.ConvertChecked:
            case ExpressionType.Decrement:
            case ExpressionType.Increment:
            case ExpressionType.IsFalse:
            case ExpressionType.IsTrue:
            case ExpressionType.OnesComplement:
            case ExpressionType.Negate:
            case ExpressionType.NegateChecked:
            case ExpressionType.Not:
            case ExpressionType.PreDecrementAssign:
            case ExpressionType.PreIncrementAssign:
            case ExpressionType.PostIncrementAssign:
            case ExpressionType.PostDecrementAssign:
            case ExpressionType.Quote:
            case ExpressionType.Throw:
            case ExpressionType.TypeAs:
            case ExpressionType.UnaryPlus:
            case ExpressionType.Unbox:
                return(Deserialize(parsedExpression as ParsedUnaryExpression));

            case ExpressionType.Extension:
            default:
                throw new NotImplementedException($"Unknown expression type {parsedExpression.NodeType}");
            }
        }
Esempio n. 17
0
        public object Evaluate(Flow flow)
        {
            if (HasErrors())
            {
                throw new EvaluationException(Error);
            }

            if (ParsedExpression == null)
            {
                ParsedExpression = Compile(OriginalExpression, (Options & EvaluateOptions.NoCache) == EvaluateOptions.NoCache);
            }

            var visitor = new EvaluationVisitor(flow, Options);

            visitor.EvaluateFunction  += EvaluateFunction;
            visitor.EvaluateParameter += EvaluateParameter;
            visitor.Parameters         = Parameters;

            // If array evaluation, execute the same expression multiple times
            if ((Options & EvaluateOptions.IterateParameters) == EvaluateOptions.IterateParameters)
            {
                var size = -1;

                ParameterEnumerators = new Dictionary <string, IEnumerator>();

                foreach (var parameter in Parameters.Values)
                {
                    if (parameter is IEnumerable enumerable)
                    {
                        var localsize = 0;

                        foreach (var o in enumerable)
                        {
                            localsize++;
                        }

                        if (size == -1)
                        {
                            size = localsize;
                        }
                        else if (localsize != size)
                        {
                            throw new EvaluationException("When IterateParameters option is used, IEnumerable parameters must have the same number of items.");
                        }
                    }
                }

                foreach (var key in Parameters.Keys)
                {
                    var parameter = Parameters[key] as IEnumerable;
                    if (parameter != null)
                    {
                        ParameterEnumerators.Add(key, parameter.GetEnumerator());
                    }
                }

                var results = new List <object>();

                for (var i = 0; i < size; i++)
                {
                    foreach (var key in ParameterEnumerators.Keys)
                    {
                        var enumerator = ParameterEnumerators[key];
                        enumerator.MoveNext();
                        Parameters[key] = enumerator.Current;
                    }

                    ParsedExpression.Accept(visitor);
                    results.Add(visitor.Result);
                }

                return(results);
            }
            else
            {
                ParsedExpression.Accept(visitor);
                return(visitor.Result);
            }
        }
Esempio n. 18
0
 internal Expression VisitParsedExpression(ParsedExpression node)
 {
     throw new NotSupportedException($"{node.GetType()} is an unsupported expression.");
 }
Esempio n. 19
0
 public BaseParsedExpression(String expr, Expression parsedExpression, BaseExpressionEvaluator ee)
 {
     this.cciExpr      = new ParsedExpression(expr, parsedExpression, ee.cciEvaluator);
     this.debugContext = null;
 }
Esempio n. 20
0
        public void Parsing()
        {
            // Input format: "Expression / ArgumentTypes"
            string tests =
                @"
a => /*1*/ a /*2*/ / int
a v => a.Length / 
(a, b) => (a + b).Length / int double
(string a, string b) => (a + b).Length / string string
(string a, string b) => (a + b).Length / string
(string a) => a.Length / string
(string a) => a.Length / int
(a) => a.Length / int
a => a.Length / int
delegate (string a) { return a.Length; } / string
(string x) => { /*1*/ x++; /*2*/ return /*3*/ x.Length; /*4*/ } / string
async () => await Task.Run(() => ""ad"") /
async () => ""ad""; // Good syntax, invalid semantics. /
a => a.Length / string
(List<Cus[]> a) => b.Length / x
/*asdf*/ a /*a*/ => /*fasd */ b.Length /*asdf */ / x
a => true / x
a => a / x
a => false / x
a => 123 / x
a => 123.0 / x
a => 123m / x
a => (int?)null / x
a => ""he\r\n\""llo"" / x
a => @""he""""llo"" / x
a => null / x
a => nulll / x
() => a / x
() => a /
{ print(a); } /
 /
a; b; /
";
            string expected = // Format: MethodParameters / MethodBody / ResultLiteral(if available), or Exception.
                              @"
(int a) { return /*1*/ a; }
DslSyntaxException: TestConcept Test: C# syntax error '(1,16): error CS1002: ; expected' in code snippet 'a v => a.Length'.
(int a, double b) { return (a + b).Length; }
(string a, string b) { return (a + b).Length; }
DslSyntaxException: TestConcept Test: The provided code snippet should have 1 parameters instead of 2. Code snippet: '(string a, string b) => (a + b).Length'. Expected parameter types: string.
(string a) { return a.Length; }
(string a) { return a.Length; }
(int a) { return a.Length; }
(int a) { return a.Length; }
DslSyntaxException: TestConcept Test: The provided code snippet should be formatted as a C# lambda expression. Code snippet 'delegate (string a) { return a.Length; }' is 'AnonymousMethodExpression' instead of 'SimpleLambdaExpression or ParenthesizedLambdaExpression'.
(string x) { /*1*/ x++; /*2*/ return /*3*/ x.Length; /*4*/ }
() { return await Task.Run(() => ""ad""); }
() { return ""ad""; }/""ad""
(string a) { return a.Length; }
(List<Cus[]> a) { return b.Length; }
(x a) { return /*fasd */ b.Length; }
(x a) { return true; }/true
(x a) { return a; }
(x a) { return false; }/false
(x a) { return 123; }/123
(x a) { return 123.0; }/123.0
(x a) { return 123m; }/123m
(x a) { return (int?)null; }
(x a) { return ""he\r\n\""llo""; }/""he\r\n\""llo""
(x a) { return @""he""""llo""; }/@""he""""llo""
(x a) { return null; }/null
(x a) { return nulll; }
DslSyntaxException: TestConcept Test: The provided code snippet should have 1 parameters instead of 0. Code snippet: '() => a'. Expected parameter types: x.
() { return a; }
DslSyntaxException: TestConcept Test: The provided code snippet should be formatted as a C# lambda expression. Code snippet '{ print(a); }' is 'Block' instead of 'ExpressionStatement'.
DslSyntaxException: TestConcept Test: The provided code snippet should be formatted as a C# lambda expression. Code snippet '' has no content. Expected content type is 'GlobalStatement'.
DslSyntaxException: TestConcept Test: The provided code snippet should be formatted as a C# lambda expression. Code snippet 'a; b;' contains multiple nodes while only one is expected. Expected child node type is 'GlobalStatement'. The provided snippet contains 2 child nodes: GlobalStatement, GlobalStatement.
";

            IConceptInfo testConcept = new TestConcept {
                Name = "Test"
            };

            var results = new List <string>();

            foreach (var test in tests.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries))
            {
                int      split          = test.LastIndexOf('/');
                string   expressionText = test.Substring(0, split).Trim();
                string[] argumentTypes  = test.Substring(split + 1).Trim().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(part => part.Trim()).ToArray();

                try
                {
                    var parsedExpression = new ParsedExpression(expressionText, argumentTypes, testConcept);
                    results.Add($"{Simplify(parsedExpression.MethodParametersAndBody)}{(parsedExpression.ResultLiteral != null ? "/" + parsedExpression.ResultLiteral : "")}");
                }
                catch (Exception e)
                {
                    results.Add($"{e.GetType().Name}: {e.Message}");
                }
            }

            string report = string.Join("\r\n", results);

            Console.WriteLine(report.Replace("\"", "\"\""));

            TestUtility.AssertAreEqualByLine(expected.Trim(), report);
        }
Esempio n. 21
0
 private string СompileSimpleExpression(string blankElectionId, string expr, int num)
 {
     var result = new StringBuilder(1024);
     result.Append(String.Format("private static int Expression{0}()", num));
     result.Append("{");
     result.Append("int result;");
     result.Append("VoteKey mask = new VoteKey();");
     var parseResult = new ParsedExpression(expr);
     bool allElections = expr.Trim().StartsWith("{@");
     string blankId = string.Empty;
     if (!allElections)
         blankId = blankElectionId;
     switch (parseResult.Type)
     {
         case ParsedExpression.ExpType.VotesSum:
             result.Append(String.Format(
                 "mask.ElectionId = \"{0}\";",
                 _template.ElectionLink.ElectionId));
             result.Append("result = Managers.VotingResultManager.VotingResults.VotesCount(mask);");
             break;
         case ParsedExpression.ExpType.MandateCount:
             result.Append("result = " + _template.ElectionLink.MaxMarks + ";");
             break;
         case ParsedExpression.ExpType.AgainstVotesCount:
             if (!_template.ElectionLink.NoneAboveExists)
             {
                 result.Append("result = 0");
             }
             else
             {
                 result.Append(String.Format(
                    "mask.ElectionId = \"{0}\"; mask.CandidateId = \"{1}\";"
                    , _template.ElectionLink.ElectionId
                    , _template.ElectionLink.NoneAboveCandidate.Id));
                 result.Append("result = Managers.VotingResultManager.VotingResults.VotesCount(mask);");
             }
             break;
         case ParsedExpression.ExpType.RestrictedCount:
             if (0 != blankId.CompareTo(string.Empty))
                 result.Append(String.Format("mask.BlankId = \"{0}\";", blankId));
             PrepareMask(result, parseResult.Restrictions);
             result.Append("result = Managers.VotingResultManager.VotingResults.VotesCount(mask);");
             break;
         default:
             throw new Exception("Неизвестный тип выражения.");
     }
     result.Append("return result;");
     result.Append("}");
     return result.ToString();
 }
Esempio n. 22
0
        private ParsedExpression ParseExpression(string expression, ISymbol classDefinition, SemanticModel semanticModel)
        {
            // Expression in DebuggerDisplayAttribute could have special qualifier, like: {ToString(), nq}
            var pieces = expression.Split(new [] { "," }, StringSplitOptions.RemoveEmptyEntries);

            if (pieces.Length > 2)
            {
                return(ParsedExpression.Invalid(expression, $"Expression should have only one specifier but got {pieces.Length - 1}"));
            }

            if (pieces.Length == 2 && !_knownSpecifiers.Contains(pieces[1].Trim()))
            {
                string additionalMessage =
                    _knownSpecifiers.Count > 1
                    ? $"Known specifiers are '{string.Join(", ", _knownSpecifiers.Select(s => $"'{s}'"))}'"
                    : $"Known specifier is '{_knownSpecifiers.First()}'";

                return(ParsedExpression.Invalid(expression,
                                                $"Unknown expression specifier '{pieces[1].Trim()}'. {additionalMessage}"));
            }

            // Ok, it seems that expression is valid, now need to check that it points to valid field/property/method
            var          originalClassDefinition = (ClassDeclarationSyntax)classDefinition.DeclaringSyntaxReferences.First().GetSyntax();
            const string magicMethodName         = "SomeMethodThatDefinitelyDoesNotExistsInOriginalClass";

            // Expressions in the attribute is very very similar to string interpolation.
            // To validate it let's create a code snippet that will use original expression
            // but in the interpolated string.
            // I.e. for expression like `DebuggerDisplay("{x}")` we'll generate:
            // var x = $"{x}";
            const string expressionToParseTemplate =
                @"private void {0}() {{
    var x = $""{{{1}}}"";
  }}";
            var expressionToParse = string.Format(expressionToParseTemplate, magicMethodName, pieces[0]);
            var tree = CSharpSyntaxTree.ParseText(expressionToParse);

            // First, need to check that expression is valid.
            var compiledUnit = (CompilationUnitSyntax)tree.GetRoot();

            if (compiledUnit.ContainsDiagnostics)
            {
                string message = string.Join(", ", compiledUnit.GetDiagnostics().Select(d => $"'{d.GetMessage()}'"));
                return(ParsedExpression.Invalid(expression, message));
            }

            // Let's add new method to the class and try to compile it.
            var parsedMember            = compiledUnit.Members[0];
            var modifiedClassDefinition = originalClassDefinition.AddMembers(parsedMember);

            // Now we need to replace old syntax tree with new one to check that new one is correct
            var oldSyntaxTree   = semanticModel.SyntaxTree;
            var compilationUnit = (CompilationUnitSyntax)oldSyntaxTree.GetRoot();

            compilationUnit = compilationUnit.WithMembers(new SyntaxList <MemberDeclarationSyntax>().Add(modifiedClassDefinition));

            var newSyntaxTree = compilationUnit.SyntaxTree;

            // Getting compilation
            var compilation = semanticModel.Compilation.ReplaceSyntaxTree(oldSyntaxTree, newSyntaxTree);

            // Compilation could fail, but we need to check that error is actually happening
            // inside our generated method (because code could be broken and could have errors).
            var relevantFailures = new List <Diagnostic>();

            foreach (var diag in compilation.GetDiagnostics().Where(d => d.Severity == DiagnosticSeverity.Error))
            {
                // Need to check that diagnostic was emitted in the generated method
                var node = diag.Location.SourceTree?.GetRoot()?.FindNode(diag.Location.SourceSpan);
                if (node == null)
                {
                    continue;
                }

                var method = node.AncestorsAndSelf().OfType <MethodDeclarationSyntax>().FirstOrDefault();
                if (method?.Identifier.Text == magicMethodName)
                {
                    relevantFailures.Add(diag);
                }
            }

            if (relevantFailures.Count > 0)
            {
                string message = string.Join(", ", relevantFailures.Select(d => $"'{d.GetMessage()}'"));
                return(ParsedExpression.Invalid(expression, message));
            }

            return(ParsedExpression.Valid(expression));
        }