diff --git a/src/NHibernate.Test/Hql/Parser/HqlParserFixture.cs b/src/NHibernate.Test/Hql/Parser/HqlParserFixture.cs new file mode 100644 index 00000000000..9eb0095ea37 --- /dev/null +++ b/src/NHibernate.Test/Hql/Parser/HqlParserFixture.cs @@ -0,0 +1,30 @@ +using Antlr.Runtime; +using NHibernate.Hql.Ast.ANTLR; +using NHibernate.Hql.Ast.ANTLR.Tree; +using NUnit.Framework; + +namespace NHibernate.Test.Hql.Parser +{ + [TestFixture] + public class HqlParserFixture + { + [Test] + public void HandlesPathWithReservedWords() + { + Assert.DoesNotThrow(() => Parse("delete from System.Object")); + Assert.DoesNotThrow(() => Parse("delete from Object.Object.Object.Object")); + } + + private static void Parse(string hql) + { + var lex = new HqlLexer(new CaseInsensitiveStringStream(hql)); + var tokens = new CommonTokenStream(lex); + + var parser = new HqlParser(tokens) + { + TreeAdaptor = new ASTTreeAdaptor(), + ParseErrorHandler = new WarningAsErrorReporter() + }.statement(); + } + } +} diff --git a/src/NHibernate.Test/Hql/Parser/WarningAsErrorReporter.cs b/src/NHibernate.Test/Hql/Parser/WarningAsErrorReporter.cs new file mode 100644 index 00000000000..5897d670698 --- /dev/null +++ b/src/NHibernate.Test/Hql/Parser/WarningAsErrorReporter.cs @@ -0,0 +1,29 @@ +using Antlr.Runtime; +using NHibernate.Hql.Ast.ANTLR; + +namespace NHibernate.Test.Hql.Parser +{ + public class WarningAsErrorReporter : IParseErrorHandler + { + public void ReportError(RecognitionException e) + { + throw e; + } + + public void ReportError(string s) + { + throw new QueryException(s); + } + + public void ReportWarning(string s) + { + throw new QueryException(s); + } + + public int GetErrorCount() => 0; + + public void ThrowQueryException() + { + } + } +} diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index a523ac5f94f..a3770c40cbf 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -46,6 +46,9 @@ + + Hql\Parser\CaseInsensitiveStringStream.cs + UtilityTest\AsyncReaderWriterLock.cs diff --git a/src/NHibernate/Hql/Ast/ANTLR/Hql.g b/src/NHibernate/Hql/Ast/ANTLR/Hql.g index 364c9142711..fa4d5467f72 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Hql.g +++ b/src/NHibernate/Hql/Ast/ANTLR/Hql.g @@ -695,10 +695,9 @@ constant path @init { -// TODO - need to clean up DotIdent - suspect that DotIdent2 supersedes the other one, but need to do the analysis -//HandleDotIdent2(); +HandleDotIdents(); } - : identifier ( DOT^ { WeakKeywords(); } identifier )* + : identifier ( DOT^ identifier )* ; // Wraps the IDENT token from the lexer, in order to provide diff --git a/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs b/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs index 35e7a520565..764cccdf873 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/HqlParser.cs @@ -112,6 +112,27 @@ protected override object RecoverFromMismatchedToken(IIntStream input, int ttype throw new MismatchedTokenException(ttype, input); } + public void HandleDotIdents() + { + int i = 2; + + while (input.LA(i) == DOT) + { + var next = input.LT(i + 1); + if (next != null) + next.Type = IDENT; + i += 2; + } + + if (input.LA(1) == IDENT || input.LA(2) != DOT) + return; + + if (IsPossibleId(input.LT(1))) + { + input.LT(1).Type = IDENT; + } + } + public void WeakKeywords() { int t = input.LA(1);