context: ///////////////////////////////////////////////////////////////////////////////////////
  // Copyright (C) 2006-2015 Esper Team. All rights reserved.                           /
  // http://esper.codehaus.org                                                          /
  // ---------------------------------------------------------------------------------- /
  // The software in this package is published under the terms of the GPL license       /
  // a copy of which has been included with this distribution in the license.txt file.  /
  ///////////////////////////////////////////////////////////////////////////////////////
  
  using System;
  using System.Collections.Generic;
  using System.IO;
  using System.Text;
  
  using Antlr4.Runtime;
  using Antlr4.Runtime.Tree;
  
  using com.espertech.esper.common.@internal.util;
  using com.espertech.esper.compat.collections;
  using com.espertech.esper.compat.logging;
  using com.espertech.esper.grammar.@internal.generated;
  
  using static com.espertech.esper.common.@internal.util.StringValue;
  
  namespace com.espertech.esper.compiler.@internal.parse
  {
      /// <summary>
      /// Utility class for AST node handling.
      /// </summary>
      public class ASTUtil
      {
          private static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
  
          private const string PROPERTY_ENABLED_AST_DUMP = "ENABLE_AST_DUMP";
  
          public static IList<String> GetIdentList(EsperEPL2GrammarParser.ColumnListKeywordAllowedContext ctx) {
              if (ctx == null || ctx.IsEmpty) {
                  return EmptyList<string>.Instance;
              }
              var parameters = new List<String>(ctx.keywordAllowedIdent().Length);
              foreach (EsperEPL2GrammarParser.KeywordAllowedIdentContext ident in ctx.keywordAllowedIdent()) {
                  parameters.Add(ident.GetText());
              }
              return parameters;
          }
  
          public static IList<string> GetIdentList(EsperEPL2GrammarParser.ColumnListContext ctx)
          {
              if (ctx == null || ctx.IsEmpty)
              {
                  return new EmptyList<string>();
              }
  
              IList<ITerminalNode> idents = ctx.IDENT();
              IList<string> parameters = new List<string>(idents.Count);
              foreach (var ident in idents)
              {
                  parameters.Add(ident.GetText());
              }
  
              return parameters;
          }
  
          public static bool IsTerminatedOfType(
              ITree child,
              int tokenType)
          {
              if (!(child is ITerminalNode))
              {
                  return false;
              }
  
              var termNode = (ITerminalNode) child;
              return termNode.Symbol.Type == tokenType;
          }
  
          public static int GetRuleIndexIfProvided(IParseTree tree)
          {
              if (!(tree is IRuleNode))
              {
                  return -1;
              }
  
              var ruleNode = (IRuleNode) tree;
              return ruleNode.RuleContext.RuleIndex;
          }
  
          public static int GetAssertTerminatedTokenType(IParseTree child)
          {
              if (!(child is ITerminalNode))
              {
                  throw ASTWalkException.From("Unexpected exception walking AST, expected terminal node", child.GetText());
              }
  
              var term = (ITerminalNode) child;
              return term.Symbol.Type;
          }
  
          public static string PrintNode(ITree node)
          {
              var writer = new StringWriter();
              ASTUtil.DumpAST(writer, node, 0);
              return writer.ToString();
          }
  
          public static bool IsRecursiveParentRule(
              RuleContext ctx,
              ISet<int> rulesIds)
          {
              var parent = ctx.Parent;
              if (parent == null)
              {
                  return false;
              }
  
              return rulesIds.Contains(parent.RuleIndex) || IsRecursiveParentRule(parent, rulesIds);
          }
  
          /// <summary>
          /// Dump the AST node to system.out.
          /// </summary>
          /// <param name="ast">to dump</param>
          public static void DumpAST(ITree ast)
          {
              if (Environment.GetEnvironmentVariable(PROPERTY_ENABLED_AST_DUMP) != null)
              {
                  var writer = new StringWriter();
  
                  RenderNode(new char[0], ast, writer);
                  DumpAST(writer, ast, 2);
  
                  Log.Info(".dumpAST ANTLR Tree dump follows...\n" + writer.ToString());
              }
          }
  
          public static void DumpAST(
              TextWriter textWriter,
              ITree ast,
              int ident)
          {
              var identChars = new char[ident];
              CompatExtensions.Fill(identChars, ' ');
  
              if (ast == null)
              {
                  RenderNode(identChars, null, textWriter);
                  return;
              }
  
              for (var i = 0; i < ast.ChildCount; i++)
              {
                  var node = ast.GetChild(i);
                  if (node == null)
                  {
                      throw new NullReferenceException("Null AST node");
                  }
  
                  RenderNode(identChars, node, textWriter);
                  DumpAST(textWriter, node, ident + 2);
              }
          }
  
          /// <summary>
          /// Print the token stream to the logger.
          /// </summary>
          /// <param name="tokens">to print</param>
          public static void PrintTokens(CommonTokenStream tokens)
          {
              if (Log.IsDebugEnabled)
              {
                  var tokenList = tokens.GetTokens();
                  var writer = new StringWriter();
                  for (var i = 0; i < tokens.Size; i++)
                  {
                      var t = (IToken) tokenList[i];
                      var text = t.Text;
                      if (string.IsNullOrWhiteSpace(text))
                      {
                          writer.Write("'" + text + "'");
                      }
                      else
                      {
                          writer.Write(text);
                      }
  
                      writer.Write('[');
                      writer.Write(t.Type);
                      writer.Write(']');
                      writer.Write(" ");
                  }
  
                  writer.WriteLine();
                  Log.Debug("Tokens: " + writer.ToString());
              }
          }
  
          private static void RenderNode(
              char[] ident,
              ITree node,
              TextWriter printer)
          {
              printer.Write(ident);
              if (node == null)
              {
                  printer.Write("NULL NODE");
              }
              else
              {
                  if (node is ParserRuleContext)
                  {
                      var ctx = (ParserRuleContext) node;
                      var ruleIndex = ctx.RuleIndex;
                      var ruleName = EsperEPL2GrammarParser.ruleNames[ruleIndex];
                      printer.Write(ruleName);
                  }
                  else
                  {
                      var terminal = (ITerminalNode) node;
                      printer.Write(terminal.Symbol.Text);
                      printer.Write(" [");
                      printer.Write(terminal.Symbol.Type);
                      printer.Write("]");
                  }
  
                  if (node is IParseTree parseTree)
                  {
  
gt:                     var parseTreeText = parseTree.GetText();