Skip to content

Commit

Permalink
bruce-dunwiddie#121 Failed parsing nested case statements
Browse files Browse the repository at this point in the history
  • Loading branch information
teyc committed Feb 5, 2023
1 parent 709090e commit bebad37
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 17 deletions.
126 changes: 109 additions & 17 deletions TSQL_Parser/TSQL_Parser/Expressions/Parsers/TSQLCaseExpressionParser.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using TSQL.Elements;
using TSQL.Tokens;
using TSQL.Tokens.Parsers;

Expand All @@ -22,21 +18,110 @@ public TSQLCaseExpression Parse(ITSQLTokenizer tokenizer)

caseExpression.Tokens.Add(tokenizer.Current);

TSQLTokenParserHelper.ReadUntilStop(
tokenizer.MoveNext();

TSQLTokenParserHelper.ReadCommentsAndWhitespace(
tokenizer,
caseExpression,
new List<TSQLFutureKeywords>() { },
new List<TSQLKeywords>() {
TSQLKeywords.END
},
lookForStatementStarts: false);

// this is different than the other clauses because the
// stop word is still part of the expression instead of
// being part of the next expression or clause like in
// the other parsers
caseExpression.Tokens);

var nextToken = tokenizer.Current ?? throw new TSQLParseException("CASE expression is incomplete. Expect WHEN or an input expression");

TSQLToken whenToken = null;

if (!nextToken.IsKeyword(TSQLKeywords.WHEN))
{
caseExpression.IsSimpleCaseExpression = true;
var valueExpr = new TSQLValueExpressionParser().Parse(tokenizer);
caseExpression.Tokens.AddRange(valueExpr.Tokens);

TSQLTokenParserHelper.ReadCommentsAndWhitespace(
tokenizer,
caseExpression.Tokens);

whenToken = tokenizer.Current;
}
else
{
caseExpression.IsSimpleCaseExpression = false;
whenToken = nextToken;
}

if (!whenToken.IsKeyword(TSQLKeywords.WHEN))
{
throw new TSQLParseException("CASE expression is incorrect. It should have a WHEN keyword, instead we have: " + whenToken.Text);
}

// 'WHEN' keyword
caseExpression.Tokens.Add(whenToken);

do
{
if (!tokenizer.MoveNext())
{
throw new TSQLParseException("CASE expression is incomplete. After WHEN, there should be an expression");
}

TSQLTokenParserHelper.ReadCommentsAndWhitespace(
tokenizer,
caseExpression.Tokens);

var whenExpr = new TSQLValueExpressionParser().Parse(tokenizer);
caseExpression.Tokens.AddRange(whenExpr.Tokens);

if (!tokenizer.Current.IsKeyword(TSQLKeywords.THEN))
{
throw new TSQLParseException(
"CASE expression is incomplete. After WHEN, there should be a THEN keyword");
}

// 'THEN' keyword
caseExpression.Tokens.Add(tokenizer.Current);

if (!tokenizer.MoveNext())
{
throw new TSQLParseException(
"CASE expression is incomplete. After THEN, there should be an expression");
}

TSQLTokenParserHelper.ReadCommentsAndWhitespace(
tokenizer,
caseExpression.Tokens);

var thenExpr = new TSQLValueExpressionParser().Parse(tokenizer);
caseExpression.Tokens.AddRange(thenExpr.Tokens);

} while (tokenizer.Current.IsKeyword(TSQLKeywords.WHEN));

if (!tokenizer.Current.IsKeyword(TSQLKeywords.ELSE))
{
throw new TSQLParseException(
"CASE expression is incomplete. There should be an ELSE keyword");
}

caseExpression.Tokens.Add(tokenizer.Current);

if (!tokenizer.MoveNext())
{
throw new TSQLParseException(
"CASE expression incomplete. There should be an expression after ELSE keyword");
}

TSQLTokenParserHelper.ReadCommentsAndWhitespace(
tokenizer,
caseExpression.Tokens);

var elseExpr = new TSQLValueExpressionParser().Parse(tokenizer);
caseExpression.Tokens.AddRange(elseExpr.Tokens);

if (!tokenizer.Current.IsKeyword(TSQLKeywords.END))
{
throw new TSQLParseException("CASE expression incomplete. There should be an END keyword");
}

// 'END' keyword
caseExpression.Tokens.Add(tokenizer.Current);

// move past the END keyword
tokenizer.MoveNext();

TSQLTokenParserHelper.ReadCommentsAndWhitespace(
Expand All @@ -45,5 +130,12 @@ public TSQLCaseExpression Parse(ITSQLTokenizer tokenizer)

return caseExpression;
}

private TSQLToken ReadNextToken(ITSQLTokenizer tokenizer)
{
if (!tokenizer.MoveNext()) return null;
return tokenizer.Current;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ public static void ReadCommentsAndWhitespace(
element.Tokens);
}

/// <summary>
/// Precondition: tokenizer.Current has not been consumed
/// Postcondition: tokenizer advanced if token consumed
/// </summary>
/// <param name="tokenizer"></param>
/// <param name="savedTokens"></param>
public static void ReadCommentsAndWhitespace(
ITSQLTokenizer tokenizer,
List<TSQLToken> savedTokens)
Expand Down

0 comments on commit bebad37

Please sign in to comment.