UPDATE
I don´t want you to do my Work and write code for me I just wanted a nurge in the right Direction!
So I have to be more specific with my Problem, give me a chance to do some work on this and I will update my question with the results ;-)
UPDATE 2
I´ve solved my Problem with Roslyn maybe not very elegant but it work for my needs, here is the code ;-)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;
namespace ParserTest
{
public class MyParser
{
private int _currentLevel = 1;
public void TestMethod()
{
string testString =
@" if(@ISEMPTY(temp.tis_filterstatus2))
{
tis_datasheet_selection.is_selected = 'Y'
}
else
{
if(@ISEMPTY(temp.tis_programmtyp_filter)) { }
else
{
AND tis_programme_v.type = '@SUB(temp.tis_programmtyp_filter)'
}
if(@ISEMPTY(temp.tis_programmfilter)) { }
else
{
AND tis_programme_v.programm LIKE '@SUB(temp.tis_programmfilter)%'
}";
var result = this.Parse(testString);
var finalResult = this.GenerateDsl(result);
}
public List<IfStatement> Parse(string strToParse)
{
var result = new List<IfStatement>();
var syntaxTree = SyntaxTree.ParseText(@"using System;class C{static void M(){" + strToParse + "}}");
var rootNodes = syntaxTree.GetRoot().DescendantNodes().Where(getRootNodes);
result = rootNodes.Select(n => ToIfStatement(n, null)).ToList();
ApplyNestingLevel(result);
return result;
}
private string GenerateDsl(List<IfStatement> list)
{
var sb = new StringBuilder();
foreach(var ifStmt in list)
{
IfStatementToDsl(ifStmt, sb);
}
return sb.ToString();
}
private string IfStatementToDsl(IfStatement ifStmt, StringBuilder sb)
{
string sqr = "";
for (int i = 0; i < ifStmt.Level; i++)
{
sqr += "'";
}
sb.Append("@IF(");
sb.Append(ifStmt.Condition.ApplyLevel(ifStmt.Level) + "," + sqr);
sb.Append(ifStmt.Statement.ApplyLevel(ifStmt.Level));
if(ifStmt.Childs.Count > 0)
{
foreach(var c in ifStmt.Childs)
{
IfStatementToDsl(c, sb);
}
}
sb.Append(sqr + "," + sqr);
if(ifStmt.Else != null)
{
sb.Append(ifStmt.Else.Statement.ApplyLevel(ifStmt.Level));
foreach(var c in ifStmt.Else.Childs)
{
IfStatementToDsl(c, sb);
}
}
sb.Append(sqr + ")");
return sb.ToString();
}
#region Parsing-Methods
private IfStatement ToIfStatement(SyntaxNode node, SyntaxNode parent)
{
var ifNode = (IfStatementSyntax)node;
var ifStmt = new IfStatement
{
Condition = ifNode.Condition.ToString(),
Statement = GetIfStatement(ifNode),
Childs = GetIfChilds(ifNode)
};
if (ifNode.Else != null)
{
ifStmt.Else = new ElseStatement
{
Statement = GetElseStatement(ifNode.Else),
Childs = GetElseChilds(ifNode.Else)
};
}
return ifStmt;
}
private List<IfStatement> GetIfChilds(IfStatementSyntax node)
{
var childs = node.Statement.DescendantNodes().Where(n => WhereIfNodes(n, node));
return childs.Select(n => ToIfStatement(n, node)).ToList();
}
private List<IfStatement> GetElseChilds(ElseClauseSyntax node)
{
var childs = node.Statement.DescendantNodes().Where(n => WhereElseNodes(n, node));
return childs.Select(n => ToIfStatement(n, node)).ToList();
}
private string GetIfStatement(IfStatementSyntax node)
{
var result = node.Statement.DescendantNodes().Where(n => WhereIfStatement(n, node));
string returnValue = "";
foreach (var n in result)
{
returnValue += n.ToString();
}
return returnValue.CleanString();
}
private string GetElseStatement(ElseClauseSyntax node)
{
var result = node.Statement.DescendantNodes().Where(n => WhereElseStatement(n, node));
string returnValue = "";
foreach (var n in result)
{
returnValue += n.ToString() + " ";
}
return returnValue.CleanString();
}
private void ApplyNestingLevel(List<IfStatement> list)
{
foreach (var item in list)
{
item.Level = _currentLevel;
if (item.Childs.Count > 0 || (item.Else != null && item.Else.Childs.Count > 0))
{
_currentLevel++;
}
ApplyNestingLevel(item.Childs);
if (item.Else != null)
{
ApplyNestingLevel(item.Else.Childs);
}
}
}
#endregion
#region Linq Where-Conditions
private bool WhereIfNodes(SyntaxNode node, IfStatementSyntax parent)
{
if(node.Kind == SyntaxKind.IfStatement && (node.Parent.Parent == parent))
{
return true;
}
return false;
}
private bool WhereElseNodes(SyntaxNode node, ElseClauseSyntax parent)
{
if (node.Kind == SyntaxKind.IfStatement && (node.Parent.Parent == parent))
{
return true;
}
return false;
}
private bool WhereIfStatement(SyntaxNode node, IfStatementSyntax parent)
{
if ((node.Kind == SyntaxKind.ExpressionStatement || node.Kind == SyntaxKind.LocalDeclarationStatement)
&& (node.Parent.Parent == parent))
{
return true;
}
return false;
}
private bool WhereElseStatement(SyntaxNode node, ElseClauseSyntax parent)
{
if ((node.Kind == SyntaxKind.ExpressionStatement || node.Kind == SyntaxKind.LocalDeclarationStatement)
&& (node.Parent.Parent == parent))
{
return true;
}
return false;
}
private Func<SyntaxNode, bool> getRootNodes =
n => n.Kind == SyntaxKind.IfStatement &&
(n.Parent.Parent.Kind != SyntaxKind.ElseClause && n.Parent.Parent.Kind != SyntaxKind.IfStatement);
#endregion
}
public class IfStatement
{
public int Level { get; set; }
public string Condition { get; set; }
public string Statement { get; set; }
public ElseStatement Else { get; set; }
public List<IfStatement> Childs { get; set; }
}
public class ElseStatement
{
public string Statement { get; set; }
public List<IfStatement> Childs { get; set; }
}
public static class Ext
{
public static string CleanString(this string value)
{
return value.Replace("\t", "").Replace("\n", "").Replace("\r", "");
}
public static string ApplyLevel(this string value, int level)
{
int multiplier = level * 2;
if (level == 0)
multiplier = 1;
var sb = new StringBuilder(multiplier);
for (int i = 0; i < multiplier; i++)
{
sb.Append("'");
}
return value.Replace("'", sb.ToString());
}
}
}
I have to write if-else Statements in a Domain-Specific-Language which is really a pain in the ass!
(The DSL is from a Third-Party-Tool which I have to use to generate WHERE-Statements for SQL-Queries)
Syntax:
@IF(@ISEMPTY(@SUB(temp.last_name))),'if true','else')
@SUB() reads a textboxvalue
Sample:
@IF(@ISEMPTY(@SUB(temp.last_name))),'','account_contact.last_name = ''DOE'' ')
you have to double your single-quotes in the else statement and if you want to nest different "if-else" every time you go a level deeper you have to double the doubled single-quotes!
You see it´s not very simple to write if you have complicated contitions...
So I thought I write a parser that transforms a normal if-else statement to this DSL-Syntax!
The Parser should create objects of this class:
public class IfCondition
{
public int ID { get; set; }
public int ParentID { get; set; }
public int Level { get; set; }
public string Condition { get; set; }
public string Content { get; set; }
public string ElseContent { get; set; }
}
based on a Collection of this Objects I could generate the DSL-Statements!
So my Problem is I really don´t have a clue, how to parse a String like this:
IF(@ISEMPTY(@SUB(temp.last_name))) { }
ELSE
{
IF(@SUB(temp.test) = 'Y')
{
account_contact.last_name = 'DOE'
}
ELSE
{
account_contat.first_name = "JOHN"
}
}
can somebody give me a nudge in the right direction?