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()); }
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); }
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()); }
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()); }
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; }
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); }
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); }
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); }
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); }
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()); } }
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 } }
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); }
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); }
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}"); } }
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); } }
internal Expression VisitParsedExpression(ParsedExpression node) { throw new NotSupportedException($"{node.GetType()} is an unsupported expression."); }
public BaseParsedExpression(String expr, Expression parsedExpression, BaseExpressionEvaluator ee) { this.cciExpr = new ParsedExpression(expr, parsedExpression, ee.cciEvaluator); this.debugContext = null; }
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); }
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(); }
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)); }