From dfa3277d85d5b1cffd6954f80a4eb4c3c819bd57 Mon Sep 17 00:00:00 2001 From: Christophe PLAT Date: Sun, 11 Jun 2023 20:37:46 +0200 Subject: [PATCH] No longer move to the next token when parsing an `is` or `as` expression (#289) --- src/DynamicExpresso.Core/Parsing/Parser.cs | 35 +++++++++++-------- test/DynamicExpresso.UnitTest/GithubIssues.cs | 23 +++++++++++- 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/src/DynamicExpresso.Core/Parsing/Parser.cs b/src/DynamicExpresso.Core/Parsing/Parser.cs index a483c49..292c720 100644 --- a/src/DynamicExpresso.Core/Parsing/Parser.cs +++ b/src/DynamicExpresso.Core/Parsing/Parser.cs @@ -481,8 +481,6 @@ private Expression ParseTypeTesting() left = Expression.TypeAs(left, knownType); else throw CreateParseException(_token.pos, ErrorMessages.SyntaxError); - - NextToken(); } return left; @@ -1443,6 +1441,22 @@ private bool TryParseKnownType(string name, out Type type) var originalPos = _token.pos; _arguments.TryGetKnownType(name, out type); + type = ParseKnownGenericType(name, type); + type = ParseTypeModifiers(type); + + if (type == null) + { + // type name couldn't be parsed: restore position + SetTextPos(originalPos); + NextToken(); + return false; + } + + return true; + } + + private Type ParseKnownGenericType(string name, Type type) + { NextToken(); if (_token.id == TokenId.LessThan) { @@ -1451,7 +1465,7 @@ private bool TryParseKnownType(string name, out Type type) // if no type was registered with the simple name, try the full generic name if (type == null && !_arguments.TryGetKnownType(name + $"`{rank}", out type)) - return false; + return null; if (rank != type.GetGenericArguments().Length) throw new ArgumentException($"The number of generic arguments provided doesn't equal the arity of the generic type definition."); @@ -1463,17 +1477,7 @@ private bool TryParseKnownType(string name, out Type type) NextToken(); } - type = ParseTypeModifiers(type); - if (type == null) - { - // type name couldn't be parsed: restore position - SetTextPos(originalPos); - NextToken(); - - return false; - } - - return true; + return type; } // we found a known type identifier, check if it has some modifiers @@ -3346,6 +3350,9 @@ private void NextToken() } if (_parsePosition == _expressionTextLength) { + if (_token.id == TokenId.End) + throw new InvalidOperationException("NextToken called when already at the end of the expression"); + t = TokenId.End; break; } diff --git a/test/DynamicExpresso.UnitTest/GithubIssues.cs b/test/DynamicExpresso.UnitTest/GithubIssues.cs index efdcaf3..9a4b446 100644 --- a/test/DynamicExpresso.UnitTest/GithubIssues.cs +++ b/test/DynamicExpresso.UnitTest/GithubIssues.cs @@ -510,7 +510,7 @@ public void GitHub_Issue_221_Case_insensitivity() // case insensivity outside lambda expressions Assert.IsFalse(interpreter.Eval("dateinthepast > now()")); // identifier - Assert.IsTrue(interpreter.Eval("dateinthepast is datetimeoffset)")); // known type + Assert.IsTrue(interpreter.Eval("dateinthepast is datetimeoffset")); // known type Assert.IsFalse(interpreter.Eval("dateinthepast.isinfuture()")); // extension method // ensure the case insensitivity option is also used in the lambda expression @@ -728,6 +728,27 @@ public void GitHub_Issue_276() var result = interpreter.Eval("((int?)5)>((double?)4)"); Assert.IsTrue(result); } + + [Test] + public void GitHub_Issue_287() + { + var interpreter = new Interpreter(); + interpreter.Reference(typeof(IEnumerable<>)); + + object str = "test"; + interpreter.SetVariable("str", str, typeof(object)); + + Assert.AreEqual(string.IsNullOrEmpty(str as string), interpreter.Eval("string.IsNullOrEmpty(str as string)")); + Assert.AreEqual(str is string, interpreter.Eval("str is string")); + Assert.AreEqual(str is int?, interpreter.Eval("str is int?")); + Assert.AreEqual(str is int[], interpreter.Eval("(str is int[])")); + Assert.AreEqual(str is int?[], interpreter.Eval("(str is int?[])")); + Assert.AreEqual(str is int?[][], interpreter.Eval("(str is int?[][])")); + Assert.AreEqual(str is IEnumerable[][], interpreter.Eval("(str is IEnumerable[][])")); + Assert.AreEqual(str is IEnumerable[][], interpreter.Eval("(str is IEnumerable[][])")); + Assert.AreEqual(str is IEnumerable[][], interpreter.Eval("(str is IEnumerable[][])")); + Assert.AreEqual(str is IEnumerable[][], interpreter.Eval("(str is IEnumerable[][])")); + } } internal static class GithubIssuesTestExtensionsMethods