Skip to content

Commit

Permalink
Fixed cannot compose schema method when matched to keyword
Browse files Browse the repository at this point in the history
  • Loading branch information
Puchaczov committed Sep 2, 2024
1 parent dcba9b3 commit 4cfa458
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 29 deletions.
33 changes: 33 additions & 0 deletions Musoq.Parser.Tests/ParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,38 @@ public void CheckReorderedQueryWithJoin_ShouldConstructQuery()

parser.ComposeAll();
}

[TestMethod]
public void CouplingSyntax_ComposeSchemaMethodWithKeywordAsMethod_ShouldParse()
{
var query = "couple #some.table with table Test as SourceOfTestValues;";

var lexer = new Lexer(query, true);
var parser = new Parser(lexer);

parser.ComposeAll();
}

[TestMethod]
public void CouplingSyntax_ComposeSchemaMethodWithWordAsMethod_ShouldParse()
{
var query = "couple #some.something with table Test as SourceOfTestValues;";

var lexer = new Lexer(query, true);
var parser = new Parser(lexer);

parser.ComposeAll();
}

[TestMethod]
public void CouplingSyntax_ComposeSchemaMethodWithWordFinishedWithNumberAsMethod_ShouldParse()
{
var query = "couple #some.something4 with table Test as SourceOfTestValues;";

var lexer = new Lexer(query, true);
var parser = new Parser(lexer);

parser.ComposeAll();
}
}
}
21 changes: 17 additions & 4 deletions Musoq.Parser/Lexing/Lexer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -212,15 +212,15 @@ private TokenType GetTokenCandidate(string tokenText, TokenDefinition matchedDef
/// <summary>
/// The token regexes set.
/// </summary>
private static class TokenRegexDefinition
public static class TokenRegexDefinition
{
private const string Keyword = @"(?<=[\s]{1,}|^){keyword}(?=[\s]{1,}|$)";
public const string Function = @"[a-zA-Z_]{1,}[a-zA-Z1-9_-]{0,}[\d]*(?=[\(])";

public static readonly string KAnd = Format(Keyword, AndToken.TokenText);
public static readonly string KComma = CommaToken.TokenText;
public static readonly string KDiff = DiffToken.TokenText;
public static readonly string KfSlashToken = Format(Keyword, FSlashToken.TokenText);
public static readonly string KFSlashToken = Format(Keyword, FSlashToken.TokenText);
public static readonly string KGreater = Format(Keyword, GreaterToken.TokenText);
public static readonly string KGreaterEqual = Format(Keyword, GreaterEqualToken.TokenText);
public static readonly string KHyphen = $@"\{HyphenToken.TokenText}";
Expand Down Expand Up @@ -253,7 +253,6 @@ private static class TokenRegexDefinition
public static readonly string KDot = "\\.";
public static readonly string KIntersect = Format(Keyword, SetOperatorToken.IntersectOperatorText);
public static readonly string KExcept = Format(Keyword, SetOperatorToken.ExceptOperatorText);
public static readonly string KCompareWith = @"(?<=[\s]{1,}|^)compare[\s]{1,}with(?=[\s]{1,}|$)";
public static readonly string KUnionAll = @"(?<=[\s]{1,}|^)union[\s]{1,}all(?=[\s]{1,}|$)";
public static readonly string KGroupBy = @"(?<=[\s]{1,}|^)group[\s]{1,}by(?=[\s]{1,}|$)";
public static readonly string KHaving = Format(Keyword, HavingToken.TokenText);
Expand Down Expand Up @@ -329,7 +328,7 @@ private static class DefinitionSets
new TokenDefinition(TokenRegexDefinition.KAnd, RegexOptions.IgnoreCase),
new TokenDefinition(TokenRegexDefinition.KComma),
new TokenDefinition(TokenRegexDefinition.KDiff),
new TokenDefinition(TokenRegexDefinition.KfSlashToken),
new TokenDefinition(TokenRegexDefinition.KFSlashToken),
new TokenDefinition(TokenRegexDefinition.KGreater),
new TokenDefinition(TokenRegexDefinition.KGreaterEqual),
new TokenDefinition(TokenRegexDefinition.KHyphen),
Expand Down Expand Up @@ -403,6 +402,20 @@ public override Token Next()
return token;
}

/// <summary>
/// Gets the next token from tokens stream that matches the regex.
/// </summary>
/// <param name="regex">The regex.</param>
/// <param name="getToken">Gets the arbitrary token.</param>
/// <returns>The token.</returns>
public override Token NextOf(Regex regex, Func<string, Token> getToken)
{
var token = base.NextOf(regex, getToken);
while (_skipWhiteSpaces && token.TokenType == TokenType.WhiteSpace)
token = base.NextOf(regex, getToken);
return token;
}

/// <summary>
/// Gets EndOfFile token.
/// </summary>
Expand Down
17 changes: 17 additions & 0 deletions Musoq.Parser/Lexing/LexerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,23 @@ public virtual TToken Next()

return AssignTokenOfType(GetEndOfFileToken);
}

public virtual TToken NextOf(Regex regex, Func<string, TToken> getToken)
{
if (IsOutOfRange)
return AssignTokenOfType(GetEndOfFileToken);

var match = regex.Match(Input, Position);

if (!match.Success || match.Index - Position != 0)
throw new UnknownTokenException(Position, Input[Position],
$"Unrecognized token exception at {Position} for {Input[Position..]}");

var token = getToken(match.Value);
Position += match.Length;

return AssignTokenOfType(() => token);
}

#endregion
}
Expand Down
2 changes: 1 addition & 1 deletion Musoq.Parser/Musoq.Parser.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>3.0.8</Version>
<Version>3.0.9</Version>
<Authors>Jakub Puchała</Authors>
<Product>Musoq</Product>
<PackageProjectUrl>https://github.com/Puchaczov/Musoq</PackageProjectUrl>
Expand Down
49 changes: 25 additions & 24 deletions Musoq.Parser/Parser.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Musoq.Parser.Lexing;
using Musoq.Parser.Nodes;
using Musoq.Parser.Nodes.From;
Expand Down Expand Up @@ -28,16 +29,7 @@ public class Parser(Lexer lexer)
{TokenType.Dot, (3, Associativity.Left)}
};

private Token Current
{
get
{
if (_hasReplacedToken)
return _replacedToken;

return lexer.Current();
}
}
private Token Current => _hasReplacedToken ? _replacedToken : lexer.Current();

private void ReplaceCurrentToken(Token newToken)
{
Expand Down Expand Up @@ -162,9 +154,12 @@ private CteExpressionNode ComposeCteExpression()

var expressions = new List<CteInnerExpressionNode>();

var col = ComposeBaseTypes() as IdentifierNode;
if (ComposeBaseTypes() is not IdentifierNode col)
{
throw new ArgumentNullException($"Expected token is {TokenType.Identifier} but received {Current.TokenType}");
}

Consume(TokenType.As);

Consume(TokenType.LeftParenthesis);
var innerSets = ComposeSetOps(0);
expressions.Add(new CteInnerExpressionNode(innerSets, col.Name));
Expand Down Expand Up @@ -622,10 +617,10 @@ private Node ComposeEqualityOperators()
private SchemaMethodFromNode ComposeSchemaMethod()
{
var schemaNode = ComposeWord();
Consume(TokenType.Dot);
var identifierNode = (IdentifierNode)ComposeBaseTypes();
ConsumeAsColumn(TokenType.Dot);
var identifier = (IdentifierNode)ComposeBaseTypes();

return new SchemaMethodFromNode(schemaNode.Value, identifierNode.Name);
return new SchemaMethodFromNode(schemaNode.Value, identifier.Name);
}

private FromNode ComposeFrom(bool fromBefore = true)
Expand Down Expand Up @@ -657,7 +652,7 @@ private FromNode ComposeFrom(bool fromBefore = true)
return fromNode;
}

if(Current.TokenType == TokenType.Function)
if (Current.TokenType == TokenType.Function)
{
var method = ComposeAccessMethod(string.Empty);
alias = ComposeAlias();
Expand Down Expand Up @@ -692,14 +687,20 @@ private WhereNode ComposeWhere(bool withoutWhereToken)

private void Consume(TokenType tokenType)
{
if (Current.TokenType.Equals(tokenType))
{
_hasReplacedToken = false;
lexer.Next();
return;
}

throw new UnexpectedTokenException<TokenType>(lexer.Position, Current);
if (!Current.TokenType.Equals(tokenType))
throw new UnexpectedTokenException<TokenType>(lexer.Position, Current);

_hasReplacedToken = false;
lexer.Next();
}

private void ConsumeAsColumn(TokenType tokenType)
{
if (!Current.TokenType.Equals(tokenType))
throw new UnexpectedTokenException<TokenType>(lexer.Position, Current);

_hasReplacedToken = false;
lexer.NextOf(new Regex(Lexer.TokenRegexDefinition.KColumn), value => new ColumnToken(value, new TextSpan(lexer.Position, lexer.Position + value.Length)));
}

private ArgsListNode ComposeArgs()
Expand Down

0 comments on commit 4cfa458

Please sign in to comment.