Skip to content

Commit

Permalink
Updates to trtree with various tree output styles.
Browse files Browse the repository at this point in the history
  • Loading branch information
kaby76 committed Sep 12, 2024
1 parent 5308bae commit e9fccd7
Show file tree
Hide file tree
Showing 4 changed files with 224 additions and 96 deletions.
284 changes: 193 additions & 91 deletions src/ParseTreeEditing/UnvParseTreeDOM/TreeOutput.cs
Original file line number Diff line number Diff line change
@@ -1,122 +1,224 @@
using Antlr4.Runtime;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection.Emit;
using System.Text;

namespace ParseTreeEditing.UnvParseTreeDOM
namespace ParseTreeEditing.UnvParseTreeDOM;

public class TreeOutput
{
public class TreeOutput
private static int changed = 0;
private static bool first_time = true;

public static StringBuilder OutputTree(UnvParseTreeNode tree, Lexer lexer, Parser parser)
{
private static int changed = 0;
private static bool first_time = true;
changed = 0;
first_time = true;
var sb = new StringBuilder();
ParenthesizedAST(tree, sb, lexer, parser);
return sb;
}

public static StringBuilder OutputTree(UnvParseTreeNode tree, Lexer lexer, Parser parser)
private static void ParenthesizedAST(UnvParseTreeNode tree, StringBuilder sb, Lexer lexer, Parser parser, int level = 0)
{
// Antlr always names a non-terminal with first letter lowercase,
// but renames it when creating the type in C#. So, remove the prefix,
// lowercase the first letter, and remove the trailing "Context" part of
// the name. Saves big time on output!
if (tree is UnvParseTreeText t)
{
changed = 0;
first_time = true;
var sb = new StringBuilder();
ParenthesizedAST(tree, sb, lexer, parser);
return sb;
StartLine(sb, level);
sb.Append(
"( "
+ " text:'" + PerformEscapes(t.Data) + "'"
+ " tt:" + t.TokenType
+ " chnl:" + lexer.ChannelNames[t.Channel]
//+ " l:" + t.Line
//+ " c:" + t.Column
//+ " si:" + t.StartIndex
//+ " ei:" + t.StopIndex
//+ " ti:" + t.TokenIndex
);
sb.AppendLine();
}

private static void ParenthesizedAST(UnvParseTreeNode tree, StringBuilder sb, Lexer lexer, Parser parser, int level = 0)
else if (tree is UnvParseTreeAttr a)
{
// Antlr always names a non-terminal with first letter lowercase,
// but renames it when creating the type in C#. So, remove the prefix,
// lowercase the first letter, and remove the trailing "Context" part of
// the name. Saves big time on output!
if (tree is UnvParseTreeText t)
StartLine(sb, level);
sb.Append("( Attribute " + a.Name as string);
sb.Append(" Value '");
sb.Append(PerformEscapes(a.StringValue));
sb.Append("'");
if (a.Channel >= 0 && a.Channel < lexer.ChannelNames.Length)
{
StartLine(sb, level);
sb.Append(
"( "
+ " text:'" + PerformEscapes(t.Data) + "'"
+ " tt:" + t.TokenType
+ " chnl:" + lexer.ChannelNames[t.Channel]
//+ " l:" + t.Line
//+ " c:" + t.Column
//+ " si:" + t.StartIndex
//+ " ei:" + t.StopIndex
//+ " ti:" + t.TokenIndex
);
sb.AppendLine();
sb.Append(" chnl:");
sb.Append(lexer.ChannelNames[a.Channel].ToString());
}
else if (tree is UnvParseTreeAttr a)
{
StartLine(sb, level);
sb.Append("( Attribute " + a.Name as string);
sb.Append(" Value '");
sb.Append(PerformEscapes(a.StringValue));
sb.Append("'");
if (a.Channel >= 0 && a.Channel < lexer.ChannelNames.Length)
{
sb.Append(" chnl:");
sb.Append(lexer.ChannelNames[a.Channel].ToString());
}
sb.AppendLine();
}
else if (tree is UnvParseTreeElement e)
{
var x = e;
var name = e.LocalName;
StartLine(sb, level);
sb.Append(
"( " + name
);
sb.AppendLine();
}
for (int i = 0; tree.ChildNodes != null && i < tree.ChildNodes.Length; ++i)
{
var c = tree.ChildNodes.item(i);
ParenthesizedAST(c as UnvParseTreeNode, sb, lexer, parser, level + 1);
}
if (level == 0)
sb.AppendLine();
}
else if (tree is UnvParseTreeElement e)
{
var x = e;
var name = e.LocalName;
StartLine(sb, level);
sb.Append(
"( " + name
);
sb.AppendLine();
}
for (int i = 0; tree.ChildNodes != null && i < tree.ChildNodes.Length; ++i)
{
var c = tree.ChildNodes.item(i);
ParenthesizedAST(c as UnvParseTreeNode, sb, lexer, parser, level + 1);
}
if (level == 0)
{
for (int k = 0; k < 1 + changed - level; ++k) sb.Append(") ");
sb.AppendLine();
changed = 0;
}
}

private static void StartLine(StringBuilder sb, int level = 0)
{
if (changed - level >= 0)
{
if (!first_time)
{
for (int j = 0; j < level; ++j) sb.Append(" ");
for (int k = 0; k < 1 + changed - level; ++k) sb.Append(") ");
sb.AppendLine();
changed = 0;
}
changed = 0;
first_time = false;
}
changed = level;
for (int j = 0; j < level; ++j) sb.Append(" ");
}

private static void StartLine(StringBuilder sb, int level = 0)
private static string ToLiteral(string input)
{
using (var writer = new StringWriter())
{
if (changed - level >= 0)
{
if (!first_time)
{
for (int j = 0; j < level; ++j) sb.Append(" ");
for (int k = 0; k < 1 + changed - level; ++k) sb.Append(") ");
sb.AppendLine();
}
changed = 0;
first_time = false;
}
changed = level;
for (int j = 0; j < level; ++j) sb.Append(" ");
var literal = input;
literal = literal.Replace("\\", "\\\\");
literal = literal.Replace("\b", "\\b");
literal = literal.Replace("\n", "\\n");
literal = literal.Replace("\t", "\\t");
literal = literal.Replace("\r", "\\r");
literal = literal.Replace("\f", "\\f");
literal = literal.Replace("\"", "\\\"");
literal = literal.Replace(string.Format("\" +{0}\t\"", Environment.NewLine), "");
return literal;
}
}

private static string ToLiteral(string input)
public static string PerformEscapes(string s)
{
StringBuilder new_s = new StringBuilder();
new_s.Append(ToLiteral(s));
return new_s.ToString();
}

public static StringBuilder OutputTreeAntlrStyle(UnvParseTreeNode tree, Lexer lexer, Parser parser)
{
changed = 0;
first_time = true;
var sb = new StringBuilder();
AntlrParenthesizedAST(tree, sb, lexer, parser);
return sb;
}

private static void AntlrParenthesizedAST(UnvParseTreeNode tree, StringBuilder sb, Lexer lexer, Parser parser, int level = 0)
{
if (tree is UnvParseTreeText t)
{
sb.Append(" " + PerformEscapes(t.Data));
return;
}
else if (tree is UnvParseTreeAttr a)
{
using (var writer = new StringWriter())
return;
}
else if (tree is UnvParseTreeElement e)
{
var x = e;
var name = e.LocalName;
sb.Append(" (" + name);
}
for (int i = 0; tree.ChildNodes != null && i < tree.ChildNodes.Length; ++i)
{
var c = tree.ChildNodes.item(i);
AntlrParenthesizedAST(c as UnvParseTreeNode, sb, lexer, parser, level + 1);
}
sb.Append(")");
}

public static StringBuilder OutputTreeIndentStyle(UnvParseTreeNode tree, Lexer lexer, Parser parser)
{
changed = 0;
first_time = true;
var sb = new StringBuilder();
IndentAST(tree, sb, lexer, parser);
return sb;
}

public static void IndentAST(UnvParseTreeNode tree, StringBuilder sb, Lexer lexer, Parser parser, int level = 0)
{
if (tree is UnvParseTreeText t)
{
IndentStartLine(sb, level);
sb.Append(
""
+ "'" + PerformEscapes(t.Data) + "'"
);
sb.AppendLine();
}
else if (tree is UnvParseTreeAttr a)
{
IndentStartLine(sb, level);
sb.Append("Attribute " + a.Name as string);
sb.Append(" Value '");
sb.Append(PerformEscapes(a.StringValue));
sb.Append("'");
if (a.Channel >= 0 && a.Channel < lexer.ChannelNames.Length)
{
var literal = input;
literal = literal.Replace("\\", "\\\\");
literal = literal.Replace("\b", "\\b");
literal = literal.Replace("\n", "\\n");
literal = literal.Replace("\t", "\\t");
literal = literal.Replace("\r", "\\r");
literal = literal.Replace("\f", "\\f");
literal = literal.Replace("\"", "\\\"");
literal = literal.Replace(string.Format("\" +{0}\t\"", Environment.NewLine), "");
return literal;
sb.Append(" chnl:");
sb.Append(lexer.ChannelNames[a.Channel].ToString());
}
sb.AppendLine();
}
else if (tree is UnvParseTreeElement e)
{
var x = e;
var name = e.LocalName;
IndentStartLine(sb, level);
sb.Append(name);
sb.AppendLine();
}
for (int i = 0; tree.ChildNodes != null && i < tree.ChildNodes.Length; ++i)
{
var c = tree.ChildNodes.item(i);
IndentAST(c as UnvParseTreeNode, sb, lexer, parser, level + 1);
}
if (level == 0)
{
sb.AppendLine();
changed = 0;
}
}

public static string PerformEscapes(string s)
private static void IndentStartLine(StringBuilder sb, int level = 0)
{
if (changed - level >= 0)
{
StringBuilder new_s = new StringBuilder();
new_s.Append(ToLiteral(s));
return new_s.ToString();
changed = 0;
first_time = false;
}
changed = level;
for (int j = 0; j < level; ++j) sb.Append(" ");
}

}
29 changes: 24 additions & 5 deletions src/trtree/Command.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,30 @@ public void Execute(Config config)
foreach (var node in nodes)
{
sb.AppendLine();
sb.AppendLine(
TreeOutput.OutputTree(
node,
lexer,
parser).ToString());
if (config.AntlrStyle)
{
sb.AppendLine(
TreeOutput.OutputTreeAntlrStyle(
node,
lexer,
parser).ToString());
}
else if (config.ParenIndentStyle)
{
sb.AppendLine(
TreeOutput.OutputTree(
node,
lexer,
parser).ToString());
}
else if (config.IndentStyle)
{
sb.AppendLine(
TreeOutput.OutputTreeIndentStyle(
node,
lexer,
parser).ToString());
}
}

System.Console.WriteLine(sb.ToString());
Expand Down
6 changes: 6 additions & 0 deletions src/trtree/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,10 @@ public class Config

[Option('a', "antlr-style", Required = false, HelpText = "Output tree as Antlr ToStringTree() style.")]
public bool AntlrStyle { get; set; }

[Option('i', "indent-style", Required = false, HelpText = "Output tree as plain indented style.")]
public bool IndentStyle { get; set; }

[Option("paren-indent-style", Required = false, HelpText = "Output tree as parenthesized indented style.")]
public bool ParenIndentStyle { get; set; }
}
1 change: 1 addition & 0 deletions src/trtree/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public void MainInternal(string[] args)
}
}
});
if (!(config.ParenIndentStyle || config.IndentStyle || config.AntlrStyle)) config.ParenIndentStyle = true;
new Command().Execute(config);
}
}

0 comments on commit e9fccd7

Please sign in to comment.