0

I'm writing down an AST (abstract syntax tree) not in tree form but with the intent of correctly formatting my code.. similar to Clang for a custom language and I'm using a StringBuilder for the effect... Right now I have to do things like:

        public string Visit(IfStatement ifStatement, int indent = 0)
        {
            var sb = new StringBuilder()
                .Append('\t', indent)
                .Append(Token.IfKeyword.ToString())
                .AppendBetween(ifStatement.Test.Accept(this), "(", ")").AppendLine()
                .Append(ifStatement.Consequent.Accept(this, indent + 1));

            if (ifStatement.Consequent != null)
            {
                sb.AppendLine()
                    .Append('\t', indent)
                    .AppendLine(Token.ElseKeyword.ToString())
                    .Append(ifStatement.Consequent.Accept(this, indent + 1));
            }

            return sb.ToString();
        }

This sometimes gets pretty complex so I was hoping I could do something like:

sb.Append("Hello").IfElse(a > 5, sb => sb.Append("world!"), sb => sb.AppendLine("ME!!")).Append(...)

Can this be done using class extensions? Thank you very much for your time!

(BTW is there a better way to write down an AST? I'm currently using the Visitor pattern for the effect but if you know a better way please let me know... I also wanted to introduce text wrapping if certain line width is reached.. don't know how to do that though).

xDGameStudios
  • 321
  • 1
  • 13
  • 1
    `sb.Append("Hello").Append(a > 5 ? "world!" : "ME!!\n").Append(...)`? – GSerg Dec 20 '19 at 21:35
  • 2
    @GSerg Probably should use `Environment.NewLine` instead of `\n`. – juharr Dec 20 '19 at 21:38
  • In my example I use AppendBetween that adds start and end text if it doesn't exist yet. For example `sb.AppendBetween("Hello", "(", ")")` return '"(Hello)"' and `sb.AppendBetween("(Hello)", "(", ")")` also returns '"(Hello)"' the AppendLine was only to give a smaller example. What if I want to do something like `sb.Append("Hello").IfElse(a > 5, sb => sb.Append("world!"), sb => sb.AppendBetween("ME!!")).Append(...)` ? – xDGameStudios Dec 20 '19 at 21:39
  • 1
    @juharr Yes, but that would be string concatenation which is weird in the context of using a stringbuilder, at which point I would rather implement an actual `IfElse` extension method. Which is pretty trivial as it's `public static StringBuilder IfElse(this StringBuilder sb, bool condition, Action if_true, Action if_false) { if (condition) { if_true(); } else { if_false(); } return sb; }`. – GSerg Dec 20 '19 at 21:46
  • 1
    Alternatively, `public static StringBuilder IfElse(this StringBuilder sb, bool condition, Action if_true, Action if_false) { if (condition) { if_true(sb); } else { if_false(sb); } return sb; }`, if the idea is to pass `sb => sb.Append()` rather than `() => sb.Append()`. – GSerg Dec 20 '19 at 21:51

1 Answers1

0

I ended up following @GSerg suggestion.

public static StringBuilder IfElse(this StringBuilder sb, bool condition, Action<StringBuilder> if_true, Action<StringBuilder> if_false) 
{ 
    if (condition) { if_true(sb); } else { if_false(sb); } return sb; 
}

and then I can do:

new StringBuilder().Append("World").IfElse(!IsNight(), sb => sb.Insert(0, "Hello ".AppendFormat(", my name is {0}", GetName())), sb => sb.Insert(0, "Bye "))

I just didn't know how the lambda thing sb => sb.Whatever() worked (I need to use functions as arguments).

xDGameStudios
  • 321
  • 1
  • 13