Skip to content

Commit

Permalink
Finished most work to parse column expressions. Still need to fix sub…
Browse files Browse the repository at this point in the history
…selects and window functions. #6
  • Loading branch information
bruce-dunwiddie committed Nov 27, 2020
1 parent 5c8b038 commit 0b95847
Show file tree
Hide file tree
Showing 16 changed files with 241 additions and 154 deletions.
113 changes: 59 additions & 54 deletions TSQL_Parser/TSQL_Parser/Clauses/Parsers/TSQLSelectClauseParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,65 +23,70 @@ public TSQLSelectClause Parse(ITSQLTokenizer tokenizer)

select.Tokens.Add(tokenizer.Current);

// need to part TOP, DISTINCT, etc here
tokenizer.MoveNext();

TSQLSubqueryHelper.ReadUntilStop(
tokenizer,
select,
new List<TSQLFutureKeywords>() { },
new List<TSQLKeywords>() {
TSQLKeywords.INTO,
TSQLKeywords.FROM,
TSQLKeywords.WHERE,
TSQLKeywords.GROUP,
TSQLKeywords.HAVING,
TSQLKeywords.ORDER,
TSQLKeywords.UNION,
TSQLKeywords.EXCEPT,
TSQLKeywords.INTERSECT,
TSQLKeywords.FOR,
TSQLKeywords.OPTION
},
lookForStatementStarts: true);
while (
tokenizer.Current != null &&
!tokenizer.Current.IsCharacter(TSQLCharacters.Semicolon) &&
!tokenizer.Current.IsCharacter(TSQLCharacters.CloseParentheses) &&
!(
tokenizer.Current.Type == TSQLTokenType.Keyword &&
(
tokenizer.Current.AsKeyword.Keyword.In(
TSQLKeywords.INTO,
TSQLKeywords.FROM,
TSQLKeywords.WHERE,
TSQLKeywords.GROUP,
TSQLKeywords.HAVING,
TSQLKeywords.ORDER,
TSQLKeywords.UNION,
TSQLKeywords.EXCEPT,
TSQLKeywords.INTERSECT,
TSQLKeywords.FOR,
TSQLKeywords.OPTION) ||
tokenizer.Current.AsKeyword.Keyword.IsStatementStart()
)
))
{
if (tokenizer.Current.IsWhitespace() ||
tokenizer.Current.IsComment() ||
tokenizer.Current.IsCharacter(TSQLCharacters.Comma))
{
select.Tokens.Add(tokenizer.Current);

tokenizer.MoveNext();
}
else if (tokenizer.Current.IsKeyword(TSQLKeywords.DISTINCT))
{
select.Tokens.Add(tokenizer.Current);

tokenizer.MoveNext();
}
else if (tokenizer.Current.IsKeyword(TSQLKeywords.TOP))
{
select.Tokens.Add(tokenizer.Current);

tokenizer.MoveNext();

// TODO: switch logic to use below once expression parsers are fully functional
//if (tokenizer.MoveNext())
//{
// if (tokenizer.Current.Type == TSQLTokenType.NumericLiteral)
// {
// select.Tokens.Add(tokenizer.Current);
// }

//while (tokenizer.MoveNext() &&
// !tokenizer.Current.IsCharacter(TSQLCharacters.Semicolon) &&
// !(
// tokenizer.Current.Type == TSQLTokenType.Keyword &&
// (
// tokenizer.Current.AsKeyword.Keyword.In(
// TSQLKeywords.INTO,
// TSQLKeywords.FROM,
// TSQLKeywords.WHERE,
// TSQLKeywords.GROUP,
// TSQLKeywords.HAVING,
// TSQLKeywords.ORDER,
// TSQLKeywords.UNION,
// TSQLKeywords.EXCEPT,
// TSQLKeywords.INTERSECT,
// TSQLKeywords.FOR,
// TSQLKeywords.OPTION) ||
// tokenizer.Current.AsKeyword.Keyword.IsStatementStart()
// )
// ))
//{
// if (tokenizer.Current.IsWhitespace() ||
// tokenizer.Current.IsComment() ||
// tokenizer.Current.IsCharacter(TSQLCharacters.Comma))
// {
// select.Tokens.Add(tokenizer.Current);
// }
// else
// {
// TSQLSelectColumn column = new TSQLSelectColumnParser().Parse(tokenizer);
// // TODO: how to handle TOP N vs TOP(N)
//}
}
else
{
TSQLSelectColumn column = new TSQLSelectColumnParser().Parse(tokenizer);

// select.Tokens.AddRange(column.Tokens);
select.Tokens.AddRange(column.Tokens);

// select.Columns.Add(column);
// }
//};
select.Columns.Add(column);
}
};

return select;
}
Expand Down
26 changes: 20 additions & 6 deletions TSQL_Parser/TSQL_Parser/Elements/Parsers/TSQLSelectColumnParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,34 @@ public TSQLSelectColumn Parse(ITSQLTokenizer tokenizer)

column.Tokens.AddRange(columnExpression.Tokens);

if (tokenizer.Current.IsKeyword(TSQLKeywords.AS))
while (
tokenizer.Current != null &&
(
tokenizer.Current.IsWhitespace() ||
tokenizer.Current.IsComment())
)
{
column.Tokens.Add(tokenizer.Current);

tokenizer.MoveNext();
}

while (
tokenizer.Current.IsWhitespace() ||
tokenizer.Current.IsComment())
if (
tokenizer.Current != null &&
tokenizer.Current.IsKeyword(TSQLKeywords.AS))
{
column.Tokens.Add(tokenizer.Current);

tokenizer.MoveNext();

while (
tokenizer.Current.IsWhitespace() ||
tokenizer.Current.IsComment())
{
column.Tokens.Add(tokenizer.Current);

tokenizer.MoveNext();
}
}

if (tokenizer.Current != null &&
Expand All @@ -46,9 +60,9 @@ public TSQLSelectColumn Parse(ITSQLTokenizer tokenizer)
column.Tokens.Add(tokenizer.Current);

column.Alias = tokenizer.Current;
}

tokenizer.MoveNext();
tokenizer.MoveNext();
}

return column;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ public TSQLCaseExpression Parse(ITSQLTokenizer tokenizer)
// the other parsers
caseExpression.Tokens.Add(tokenizer.Current);

tokenizer.MoveNext();

return caseExpression;
}
}
Expand Down
130 changes: 128 additions & 2 deletions TSQL_Parser/TSQL_Parser/Expressions/Parsers/TSQLExpressionFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ private TSQLExpression ParseNext(
group.Tokens.Add(tokenizer.Current);
}

// TODO: handle subselect starting with SELECT vs an expression

group.InnerExpression = Parse(tokenizer);
group.Tokens.AddRange(group.InnerExpression.Tokens);

Expand Down Expand Up @@ -166,7 +168,41 @@ private TSQLExpression ParseNext(
else if (tokenizer.Current.Type.In(
TSQLTokenType.SystemIdentifier))
{
return new TSQLFunctionExpression();
TSQLFunctionExpression function = new TSQLFunctionExpression();

function.Name = tokenizer.Current.Text;

function.Tokens.Add(tokenizer.Current);

if (tokenizer.MoveNext() &&
tokenizer.Current.IsCharacter(TSQLCharacters.OpenParentheses))
{
function.Tokens.Add(tokenizer.Current);

TSQLArgumentList arguments = new TSQLArgumentListParser().Parse(
tokenizer);

function.Tokens.AddRange(arguments.Tokens);

function.Arguments = arguments;

if (tokenizer.Current.IsCharacter(TSQLCharacters.CloseParentheses))
{
function.Tokens.Add(tokenizer.Current);
}

while (
tokenizer.MoveNext() &&
(
tokenizer.Current.IsWhitespace() ||
tokenizer.Current.IsComment())
)
{
function.Tokens.Add(tokenizer.Current);
}
}

return function;
}
else if (tokenizer.Current.Type.In(
TSQLTokenType.Identifier))
Expand All @@ -184,6 +220,8 @@ private TSQLExpression ParseNext(

// alias would be any tokens prior to last period, removing whitespace, concatenated together as string

// TODO: handle window functions with multiple parts

List<TSQLToken> tokens = new List<TSQLToken>();

tokens.Add(tokenizer.Current);
Expand All @@ -203,10 +241,98 @@ private TSQLExpression ParseNext(
function.Tokens.AddRange(arguments.Tokens);

function.Arguments = arguments;

if (tokenizer.Current.IsCharacter(TSQLCharacters.CloseParentheses))
{
function.Tokens.Add(tokenizer.Current);
}

function.Name =
String.Join(
"",
tokens
.Where(t => !t.IsComment() && !t.IsWhitespace())
.Select(t => t.Text));

while (
tokenizer.MoveNext() &&
(
tokenizer.Current.IsWhitespace() ||
tokenizer.Current.IsComment())
)
{
function.Tokens.Add(tokenizer.Current);
}

return function;
}
else if (tokenizer.Current.Text == "*")
{
// e.g. p.*

TSQLMulticolumnExpression multi = new TSQLMulticolumnExpression();

multi.Tokens.AddRange(tokens);

multi.Tokens.Add(tokenizer.Current);

string alias =
String.Join(
"",
tokens
.Where(t => !t.IsComment() && !t.IsWhitespace())
.Select(t => t.Text));

// trim off the last period
multi.TableAlias = alias.Substring(0, alias.Length - 1);

while (
tokenizer.MoveNext() &&
(
tokenizer.Current.IsWhitespace() ||
tokenizer.Current.IsComment())
)
{
multi.Tokens.Add(tokenizer.Current);
}

return multi;
}
else if (
tokenizer.Current.IsCharacter(TSQLCharacters.Comma) ||
tokenizer.Current.IsCharacter(TSQLCharacters.CloseParentheses) ||
tokenizer.Current.Type == TSQLTokenType.Keyword)
{
TSQLColumnExpression column = new TSQLColumnExpression();

column.Tokens.AddRange(tokens);

string alias =
String.Join(
"",
tokens
.Where(t => !t.IsComment() && !t.IsWhitespace())
.Select(t => t.Text));

// trim off the last period
column.TableAlias = alias.Substring(0, alias.Length - 1);

tokens.Reverse();

column.Column = tokens
.Where(t => !t.IsComment() && !t.IsWhitespace())
.Select(t => t.Text)
.First();

return column;
}
else
{
tokens.Add(tokenizer.Current);
}
}

return new TSQLFunctionExpression();
return null;
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,6 @@ public override TSQLExpressionType Type
}
}

public string TableAlias
{
get
{
return null;
}
}
public string TableAlias { get; internal set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,6 @@ public TSQLDeleteStatement Parse()

Statement.Tokens.AddRange(optionClause.Tokens);
}

if (
Tokenizer.Current?.AsKeyword != null &&
Tokenizer.Current.AsKeyword.Keyword.IsStatementStart())
{
Tokenizer.Putback();
}

return Statement;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,6 @@ public TSQLExecuteStatement Parse()
new List<TSQLKeywords>() { },
lookForStatementStarts: true);

if (
Tokenizer.Current?.AsKeyword != null &&
Tokenizer.Current.AsKeyword.Keyword.IsStatementStart())
{
Tokenizer.Putback();
}

return Statement;
}

Expand Down
Loading

0 comments on commit 0b95847

Please sign in to comment.