// examples/parse translated by mycpp

#include "mycpp/examples/parse_preamble.h"
// BEGIN mycpp output

#include "mycpp/runtime.h"

GLOBAL_STR(str0, "(");
GLOBAL_STR(str1, ")");
GLOBAL_STR(str2, "_");
GLOBAL_STR(str3, "T");
GLOBAL_STR(str4, "F");
GLOBAL_STR(str5, "\n<html>\n  <head>\n     <title>oil AST</title>\n     <style>\n      .n { color: brown }\n      .s { font-weight: bold }\n      .o { color: darkgreen }\n     </style>\n  </head>\n  <body>\n    <pre>\n");
GLOBAL_STR(str6, "\n    </pre>\n  </body>\n</html>\n    ");
GLOBAL_STR(str7, "n");
GLOBAL_STR(str8, "s");
GLOBAL_STR(str9, "o");
GLOBAL_STR(str10, "o");
GLOBAL_STR(str11, "o");
GLOBAL_STR(str12, "<span class=\"%s\">");
GLOBAL_STR(str13, "</span>");
GLOBAL_STR(str14, " ");
GLOBAL_STR(str15, "\n");
GLOBAL_STR(str16, " ");
GLOBAL_STR(str17, "]");
GLOBAL_STR(str18, " ");
GLOBAL_STR(str19, " ");
GLOBAL_STR(str20, "\n");
GLOBAL_STR(str21, "\n");
GLOBAL_STR(str22, " ");
GLOBAL_STR(str23, "%s%s: [");
GLOBAL_STR(str24, "\n");
GLOBAL_STR(str25, "\n");
GLOBAL_STR(str26, "%s]");
GLOBAL_STR(str27, "%s%s: ");
GLOBAL_STR(str28, "\n");
GLOBAL_STR(str29, "\n");
GLOBAL_STR(str30, " ");
GLOBAL_STR(str31, "UNTYPED any");
GLOBAL_STR(str32, "...0x%s");
GLOBAL_STR(str33, " ");
GLOBAL_STR(str34, " ");
GLOBAL_STR(str35, " %s:");
GLOBAL_STR(str36, "UNTYPED any");
GLOBAL_STR(str37, "[");
GLOBAL_STR(str38, " ");
GLOBAL_STR(str39, "]");
GLOBAL_STR(str40, "...0x%s");
GLOBAL_STR(str41, "foo");
GLOBAL_STR(str42, "\n");
GLOBAL_STR(str43, "\u001b[0;0m");
GLOBAL_STR(str44, "\u001b[1m");
GLOBAL_STR(str45, "\u001b[4m");
GLOBAL_STR(str46, "\u001b[7m");
GLOBAL_STR(str47, "\u001b[31m");
GLOBAL_STR(str48, "\u001b[32m");
GLOBAL_STR(str49, "\u001b[33m");
GLOBAL_STR(str50, "\u001b[34m");
GLOBAL_STR(str51, "\u001b[35m");
GLOBAL_STR(str52, "\u001b[36m");
GLOBAL_STR(str53, "\u001b[37m");
GLOBAL_STR(str54, "\n");
GLOBAL_STR(str55, "");
GLOBAL_STR(str56, "+-");
GLOBAL_STR(str57, "*/");
GLOBAL_STR(str58, "()");
GLOBAL_STR(str59, "");
GLOBAL_STR(str60, "Expected ");
GLOBAL_STR(str61, "(");
GLOBAL_STR(str62, ")");
GLOBAL_STR(str63, "Unexpected token ");
GLOBAL_STR(str64, "abc");
GLOBAL_STR(str65, "tok_val %s");
GLOBAL_STR(str66, "1+2");
GLOBAL_STR(str67, "1+2*3");
GLOBAL_STR(str68, "1*2+3");
GLOBAL_STR(str69, "(1+2)*3");
GLOBAL_STR(str70, "a+b+c+d");
GLOBAL_STR(str71, "a*b*3*4");
GLOBAL_STR(str72, "1");
GLOBAL_STR(str73, "a");
GLOBAL_STR(str74, "(");
GLOBAL_STR(str75, ")");
GLOBAL_STR(str76, "(a+b");
GLOBAL_STR(str77, " ");
GLOBAL_STR(str78, " $$ ");
GLOBAL_STR(str79, "");
GLOBAL_STR(str80, "--");
GLOBAL_STR(str81, "%s =>");
GLOBAL_STR(str82, "Parse error: %s");
GLOBAL_STR(str83, "\n");
GLOBAL_STR(str84, "Const %d");
GLOBAL_STR(str85, "Var %s");
GLOBAL_STR(str86, "Other");
GLOBAL_STR(str87, "c.i %d");
GLOBAL_STR(str88, "v.name %r");
GLOBAL_STR(str89, "b.op %r");
GLOBAL_STR(str90, "+");
GLOBAL_STR(str91, "\n");
GLOBAL_STR(str92, "a*b*3*4");
GLOBAL_STR(str93, "result = %d");
GLOBAL_STR(str94, "iterations = %d");
GLOBAL_STR(str95, "&");
GLOBAL_STR(str96, "&amp;");
GLOBAL_STR(str97, "<");
GLOBAL_STR(str98, "&lt;");
GLOBAL_STR(str99, ">");
GLOBAL_STR(str100, "&gt;");

namespace runtime {  // forward declare

  class TraversalState;

}  // forward declare namespace runtime

namespace format {  // forward declare

  class ColorOutput;
  class TextOutput;
  class HtmlOutput;
  class AnsiOutput;
  class _PrettyPrinter;

}  // forward declare namespace format

namespace j8_lite {  // forward declare


}  // forward declare namespace j8_lite

namespace ansi {  // forward declare


}  // forward declare namespace ansi

namespace pretty {  // forward declare

  class PrettyPrinter;

}  // forward declare namespace pretty

namespace parse {  // forward declare

  class Lexer;
  class ParseError;
  class Parser;

}  // forward declare namespace parse

namespace cgi {  // forward declare


}  // forward declare namespace cgi

namespace runtime {  // declare

using hnode_asdl::hnode;
extern int NO_SPID;
hnode::Record* NewRecord(BigStr* node_type);
hnode::Leaf* NewLeaf(BigStr* s, hnode_asdl::color_t e_color);
class TraversalState {
 public:
  TraversalState();
  Dict<int, bool>* seen;
  Dict<int, int>* ref_count;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(2, sizeof(TraversalState));
  }

  DISALLOW_COPY_AND_ASSIGN(TraversalState)
};

extern BigStr* TRUE_STR;
extern BigStr* FALSE_STR;

}  // declare namespace runtime

namespace format {  // declare

using hnode_asdl::hnode;
format::ColorOutput* DetectConsoleOutput(mylib::Writer* f);
class ColorOutput {
 public:
  ColorOutput(mylib::Writer* f);
  virtual format::ColorOutput* NewTempBuffer();
  virtual void FileHeader();
  virtual void FileFooter();
  virtual void PushColor(hnode_asdl::color_t e_color);
  virtual void PopColor();
  virtual void write(BigStr* s);
  void WriteRaw(Tuple2<BigStr*, int>* raw);
  int NumChars();
  Tuple2<BigStr*, int> GetRaw();
  mylib::Writer* f;
  int num_chars;
  
  static constexpr uint32_t field_mask() {
    return maskbit(offsetof(ColorOutput, f));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(ColorOutput));
  }

  DISALLOW_COPY_AND_ASSIGN(ColorOutput)
};

class TextOutput : public ::format::ColorOutput {
 public:
  TextOutput(mylib::Writer* f);
  virtual format::TextOutput* NewTempBuffer();
  virtual void PushColor(hnode_asdl::color_t e_color);
  virtual void PopColor();
  
  static constexpr uint32_t field_mask() {
    return ::format::ColorOutput::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(TextOutput));
  }

  DISALLOW_COPY_AND_ASSIGN(TextOutput)
};

class HtmlOutput : public ::format::ColorOutput {
 public:
  HtmlOutput(mylib::Writer* f);
  virtual format::HtmlOutput* NewTempBuffer();
  virtual void FileHeader();
  virtual void FileFooter();
  virtual void PushColor(hnode_asdl::color_t e_color);
  virtual void PopColor();
  virtual void write(BigStr* s);
  
  static constexpr uint32_t field_mask() {
    return ::format::ColorOutput::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(HtmlOutput));
  }

  DISALLOW_COPY_AND_ASSIGN(HtmlOutput)
};

class AnsiOutput : public ::format::ColorOutput {
 public:
  AnsiOutput(mylib::Writer* f);
  virtual format::AnsiOutput* NewTempBuffer();
  virtual void PushColor(hnode_asdl::color_t e_color);
  virtual void PopColor();
  
  static constexpr uint32_t field_mask() {
    return ::format::ColorOutput::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(AnsiOutput));
  }

  DISALLOW_COPY_AND_ASSIGN(AnsiOutput)
};

extern int INDENT;
class _PrettyPrinter {
 public:
  _PrettyPrinter(int max_col);
  bool _PrintWrappedArray(List<hnode_asdl::hnode_t*>* array, int prefix_len, format::ColorOutput* f, int indent);
  bool _PrintWholeArray(List<hnode_asdl::hnode_t*>* array, int prefix_len, format::ColorOutput* f, int indent);
  void _PrintRecord(hnode::Record* node, format::ColorOutput* f, int indent);
  void PrintNode(hnode_asdl::hnode_t* node, format::ColorOutput* f, int indent);
  int max_col;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(0, sizeof(_PrettyPrinter));
  }

  DISALLOW_COPY_AND_ASSIGN(_PrettyPrinter)
};

bool _TrySingleLineObj(hnode::Record* node, format::ColorOutput* f, int max_chars);
bool _TrySingleLine(hnode_asdl::hnode_t* node, format::ColorOutput* f, int max_chars);
void PrintTree(hnode_asdl::hnode_t* node, format::ColorOutput* f);
void PrintTree2(hnode_asdl::hnode_t* node, format::ColorOutput* f);

}  // declare namespace format

namespace j8_lite {  // declare

BigStr* EncodeString(BigStr* s, bool unquoted_ok = false);
BigStr* YshEncodeString(BigStr* s);
BigStr* MaybeShellEncode(BigStr* s);
BigStr* ShellEncode(BigStr* s);
BigStr* YshEncode(BigStr* s, bool unquoted_ok = false);

}  // declare namespace j8_lite

namespace ansi {  // declare

extern BigStr* RESET;
extern BigStr* BOLD;
extern BigStr* UNDERLINE;
extern BigStr* REVERSE;
extern BigStr* RED;
extern BigStr* GREEN;
extern BigStr* YELLOW;
extern BigStr* BLUE;
extern BigStr* MAGENTA;
extern BigStr* CYAN;
extern BigStr* WHITE;

}  // declare namespace ansi

namespace pretty {  // declare

pretty_asdl::Measure* _EmptyMeasure();
pretty_asdl::Measure* _FlattenMeasure(pretty_asdl::Measure* measure);
pretty_asdl::Measure* _ConcatMeasure(pretty_asdl::Measure* m1, pretty_asdl::Measure* m2);
int _SuffixLen(pretty_asdl::Measure* measure);
pretty_asdl::MeasuredDoc* AsciiText(BigStr* string);
pretty_asdl::MeasuredDoc* _Break(BigStr* string);
pretty_asdl::MeasuredDoc* _Indent(int indent, pretty_asdl::MeasuredDoc* mdoc);
pretty_asdl::MeasuredDoc* _Concat(List<pretty_asdl::MeasuredDoc*>* mdocs);
pretty_asdl::MeasuredDoc* _Group(pretty_asdl::MeasuredDoc* mdoc);
pretty_asdl::MeasuredDoc* _IfFlat(pretty_asdl::MeasuredDoc* flat_mdoc, pretty_asdl::MeasuredDoc* nonflat_mdoc);
pretty_asdl::MeasuredDoc* _Flat(pretty_asdl::MeasuredDoc* mdoc);
class PrettyPrinter {
 public:
  PrettyPrinter(int max_width);
  bool _Fits(int prefix_len, doc::Group* group, pretty_asdl::Measure* suffix_measure);
  void PrintDoc(pretty_asdl::MeasuredDoc* document, mylib::BufWriter* buf);
  int max_width;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(0, sizeof(PrettyPrinter));
  }

  DISALLOW_COPY_AND_ASSIGN(PrettyPrinter)
};


}  // declare namespace pretty

namespace parse {  // declare

class Lexer {
 public:
  Lexer(BigStr* s);
  Tuple2<expr_asdl::tok_t, BigStr*> Read();
  void _MethodCallingOtherMethod();
  BigStr* s;
  int i;
  int n;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(1, sizeof(Lexer));
  }

  DISALLOW_COPY_AND_ASSIGN(Lexer)
};

class ParseError {
 public:
  ParseError(BigStr* msg);
  BigStr* msg;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(1, sizeof(ParseError));
  }

  DISALLOW_COPY_AND_ASSIGN(ParseError)
};

class Parser {
 public:
  Parser(parse::Lexer* lexer);
  void Next();
  void Eat(BigStr* tok_val);
  expr_asdl::expr_t* ParseFactor();
  expr_asdl::expr_t* ParseTerm();
  expr_asdl::expr_t* ParseExpr();
  expr_asdl::expr_t* Parse();
  parse::Lexer* lexer;
  BigStr* tok_val;
  expr_asdl::tok_t tok_type;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(2, sizeof(Parser));
  }

  DISALLOW_COPY_AND_ASSIGN(Parser)
};

void TestParse();
void TestCreateNull();
void run_tests();
void run_benchmarks();

}  // declare namespace parse

namespace cgi {  // declare

BigStr* escape(BigStr* s);

}  // declare namespace cgi

namespace runtime {  // define

using hnode_asdl::hnode;
using hnode_asdl::color_t;
using hnode_asdl::color_e;
int NO_SPID = -1;

hnode::Record* NewRecord(BigStr* node_type) {
  StackRoot _root0(&node_type);

  return Alloc<hnode::Record>(node_type, Alloc<List<hnode_asdl::Field*>>(), false, str0, str1, Alloc<List<hnode_asdl::hnode_t*>>());
}

hnode::Leaf* NewLeaf(BigStr* s, hnode_asdl::color_t e_color) {
  StackRoot _root0(&s);

  if (s == nullptr) {
    return Alloc<hnode::Leaf>(str2, color_e::OtherConst);
  }
  else {
    return Alloc<hnode::Leaf>(s, e_color);
  }
}

TraversalState::TraversalState() {
  this->seen = Alloc<Dict<int, bool>>();
  this->ref_count = Alloc<Dict<int, int>>();
}
BigStr* TRUE_STR = str3;
BigStr* FALSE_STR = str4;

}  // define namespace runtime

namespace format {  // define

using hnode_asdl::hnode;
using hnode_asdl::hnode_e;
using hnode_asdl::hnode_t;
using hnode_asdl::color_e;
using hnode_asdl::color_t;

format::ColorOutput* DetectConsoleOutput(mylib::Writer* f) {
  StackRoot _root0(&f);

  if (f->isatty()) {
    return Alloc<AnsiOutput>(f);
  }
  else {
    return Alloc<TextOutput>(f);
  }
}

ColorOutput::ColorOutput(mylib::Writer* f) {
  this->f = f;
  this->num_chars = 0;
}

format::ColorOutput* ColorOutput::NewTempBuffer() {
  FAIL(kNotImplemented);  // Python NotImplementedError
}

void ColorOutput::FileHeader() {
  ;  // pass
}

void ColorOutput::FileFooter() {
  ;  // pass
}

void ColorOutput::PushColor(hnode_asdl::color_t e_color) {
  FAIL(kNotImplemented);  // Python NotImplementedError
}

void ColorOutput::PopColor() {
  FAIL(kNotImplemented);  // Python NotImplementedError
}

void ColorOutput::write(BigStr* s) {
  StackRoot _root0(&s);

  this->f->write(s);
  this->num_chars += len(s);
}

void ColorOutput::WriteRaw(Tuple2<BigStr*, int>* raw) {
  BigStr* s = nullptr;
  int num_chars;
  StackRoot _root0(&raw);
  StackRoot _root1(&s);

  Tuple2<BigStr*, int>* tup0 = raw;
  s = tup0->at0();
  num_chars = tup0->at1();
  this->f->write(s);
  this->num_chars += num_chars;
}

int ColorOutput::NumChars() {
  return this->num_chars;
}

Tuple2<BigStr*, int> ColorOutput::GetRaw() {
  mylib::BufWriter* f = nullptr;
  StackRoot _root0(&f);

  f = static_cast<mylib::BufWriter*>(this->f);
  return Tuple2<BigStr*, int>(f->getvalue(), this->num_chars);
}

TextOutput::TextOutput(mylib::Writer* f) : ::format::ColorOutput(f) {
}

format::TextOutput* TextOutput::NewTempBuffer() {
  return Alloc<TextOutput>(Alloc<mylib::BufWriter>());
}

void TextOutput::PushColor(hnode_asdl::color_t e_color) {
  ;  // pass
}

void TextOutput::PopColor() {
  ;  // pass
}

HtmlOutput::HtmlOutput(mylib::Writer* f) : ::format::ColorOutput(f) {
}

format::HtmlOutput* HtmlOutput::NewTempBuffer() {
  return Alloc<HtmlOutput>(Alloc<mylib::BufWriter>());
}

void HtmlOutput::FileHeader() {
  this->f->write(str5);
}

void HtmlOutput::FileFooter() {
  this->f->write(str6);
}

void HtmlOutput::PushColor(hnode_asdl::color_t e_color) {
  BigStr* css_class = nullptr;
  StackRoot _root0(&css_class);

  if (e_color == color_e::TypeName) {
    css_class = str7;
  }
  else {
    if (e_color == color_e::StringConst) {
      css_class = str8;
    }
    else {
      if (e_color == color_e::OtherConst) {
        css_class = str9;
      }
      else {
        if (e_color == color_e::External) {
          css_class = str10;
        }
        else {
          if (e_color == color_e::UserType) {
            css_class = str11;
          }
          else {
            assert(0);  // AssertionError
          }
        }
      }
    }
  }
  this->f->write(StrFormat("<span class=\"%s\">", css_class));
}

void HtmlOutput::PopColor() {
  this->f->write(str13);
}

void HtmlOutput::write(BigStr* s) {
  StackRoot _root0(&s);

  this->f->write(cgi::escape(s));
  this->num_chars += len(s);
}

AnsiOutput::AnsiOutput(mylib::Writer* f) : ::format::ColorOutput(f) {
}

format::AnsiOutput* AnsiOutput::NewTempBuffer() {
  return Alloc<AnsiOutput>(Alloc<mylib::BufWriter>());
}

void AnsiOutput::PushColor(hnode_asdl::color_t e_color) {
  if (e_color == color_e::TypeName) {
    this->f->write(ansi::YELLOW);
  }
  else {
    if (e_color == color_e::StringConst) {
      this->f->write(ansi::BOLD);
    }
    else {
      if (e_color == color_e::OtherConst) {
        this->f->write(ansi::GREEN);
      }
      else {
        if (e_color == color_e::External) {
          this->f->write(str_concat(ansi::BOLD, ansi::BLUE));
        }
        else {
          if (e_color == color_e::UserType) {
            this->f->write(ansi::GREEN);
          }
          else {
            assert(0);  // AssertionError
          }
        }
      }
    }
  }
}

void AnsiOutput::PopColor() {
  this->f->write(ansi::RESET);
}
int INDENT = 2;

_PrettyPrinter::_PrettyPrinter(int max_col) {
  this->max_col = max_col;
}

bool _PrettyPrinter::_PrintWrappedArray(List<hnode_asdl::hnode_t*>* array, int prefix_len, format::ColorOutput* f, int indent) {
  bool all_fit;
  int chars_so_far;
  int i;
  format::ColorOutput* single_f = nullptr;
  BigStr* s = nullptr;
  int num_chars;
  StackRoot _root0(&array);
  StackRoot _root1(&f);
  StackRoot _root2(&single_f);
  StackRoot _root3(&s);

  all_fit = true;
  chars_so_far = prefix_len;
  i = 0;
  for (ListIter<hnode_asdl::hnode_t*> it(array); !it.Done(); it.Next(), ++i) {
    hnode_asdl::hnode_t* val = it.Value();
    StackRoot _for(&val  );
    if (i != 0) {
      f->write(str14);
    }
    single_f = f->NewTempBuffer();
    if (_TrySingleLine(val, single_f, (this->max_col - chars_so_far))) {
      Tuple2<BigStr*, int> tup1 = single_f->GetRaw();
      s = tup1.at0();
      num_chars = tup1.at1();
      f->WriteRaw((Alloc<Tuple2<BigStr*, int>>(s, num_chars)));
      chars_so_far += single_f->NumChars();
    }
    else {
      f->write(str15);
      this->PrintNode(val, f, (indent + INDENT));
      chars_so_far = 0;
      all_fit = false;
    }
  }
  return all_fit;
}

bool _PrettyPrinter::_PrintWholeArray(List<hnode_asdl::hnode_t*>* array, int prefix_len, format::ColorOutput* f, int indent) {
  bool all_fit;
  List<Tuple2<BigStr*, int>*>* pieces = nullptr;
  int chars_so_far;
  format::ColorOutput* single_f = nullptr;
  BigStr* s = nullptr;
  int num_chars;
  int i;
  StackRoot _root0(&array);
  StackRoot _root1(&f);
  StackRoot _root2(&pieces);
  StackRoot _root3(&single_f);
  StackRoot _root4(&s);

  all_fit = true;
  pieces = Alloc<List<Tuple2<BigStr*, int>*>>();
  chars_so_far = prefix_len;
  for (ListIter<hnode_asdl::hnode_t*> it(array); !it.Done(); it.Next()) {
    hnode_asdl::hnode_t* item = it.Value();
    StackRoot _for(&item  );
    single_f = f->NewTempBuffer();
    if (_TrySingleLine(item, single_f, (this->max_col - chars_so_far))) {
      Tuple2<BigStr*, int> tup2 = single_f->GetRaw();
      s = tup2.at0();
      num_chars = tup2.at1();
      pieces->append((Alloc<Tuple2<BigStr*, int>>(s, num_chars)));
      chars_so_far += single_f->NumChars();
    }
    else {
      all_fit = false;
      break;
    }
  }
  if (all_fit) {
    i = 0;
    for (ListIter<Tuple2<BigStr*, int>*> it(pieces); !it.Done(); it.Next(), ++i) {
      Tuple2<BigStr*, int>* p = it.Value();
      StackRoot _for(&p    );
      if (i != 0) {
        f->write(str16);
      }
      f->WriteRaw(p);
    }
    f->write(str17);
  }
  return all_fit;
}

void _PrettyPrinter::_PrintRecord(hnode::Record* node, format::ColorOutput* f, int indent) {
  BigStr* ind = nullptr;
  BigStr* prefix = nullptr;
  int prefix_len;
  bool all_fit;
  BigStr* name = nullptr;
  hnode_asdl::hnode_t* val = nullptr;
  BigStr* ind1 = nullptr;
  hnode_asdl::hnode_t* UP_val = nullptr;
  int tag;
  BigStr* name_str = nullptr;
  format::ColorOutput* single_f = nullptr;
  BigStr* s = nullptr;
  int num_chars;
  StackRoot _root0(&node);
  StackRoot _root1(&f);
  StackRoot _root2(&ind);
  StackRoot _root3(&prefix);
  StackRoot _root4(&name);
  StackRoot _root5(&val);
  StackRoot _root6(&ind1);
  StackRoot _root7(&UP_val);
  StackRoot _root8(&name_str);
  StackRoot _root9(&single_f);
  StackRoot _root10(&s);

  ind = str_repeat(str18, indent);
  if (node->abbrev) {
    prefix = str_concat(ind, node->left);
    f->write(prefix);
    if (len(node->node_type)) {
      f->PushColor(color_e::TypeName);
      f->write(node->node_type);
      f->PopColor();
      f->write(str19);
    }
    prefix_len = ((len(prefix) + len(node->node_type)) + 1);
    all_fit = this->_PrintWrappedArray(node->unnamed_fields, prefix_len, f, indent);
    if (!all_fit) {
      f->write(str20);
      f->write(ind);
    }
    f->write(node->right);
  }
  else {
    f->write(str_concat(ind, node->left));
    f->PushColor(color_e::TypeName);
    f->write(node->node_type);
    f->PopColor();
    f->write(str21);
    for (ListIter<hnode_asdl::Field*> it(node->fields); !it.Done(); it.Next()) {
      hnode_asdl::Field* field = it.Value();
      StackRoot _for(&field    );
      name = field->name;
      val = field->val;
      ind1 = str_repeat(str22, (indent + INDENT));
      UP_val = val;
      tag = val->tag();
      if (tag == hnode_e::Array) {
        hnode::Array* val = static_cast<hnode::Array*>(UP_val);
        name_str = StrFormat("%s%s: [", ind1, name);
        f->write(name_str);
        prefix_len = len(name_str);
        if (!this->_PrintWholeArray(val->children, prefix_len, f, indent)) {
          f->write(str24);
          for (ListIter<hnode_asdl::hnode_t*> it(val->children); !it.Done(); it.Next()) {
            hnode_asdl::hnode_t* child = it.Value();
            StackRoot _for(&child          );
            this->PrintNode(child, f, ((indent + INDENT) + INDENT));
            f->write(str25);
          }
          f->write(StrFormat("%s]", ind1));
        }
      }
      else {
        name_str = StrFormat("%s%s: ", ind1, name);
        f->write(name_str);
        prefix_len = len(name_str);
        single_f = f->NewTempBuffer();
        if (_TrySingleLine(val, single_f, (this->max_col - prefix_len))) {
          Tuple2<BigStr*, int> tup3 = single_f->GetRaw();
          s = tup3.at0();
          num_chars = tup3.at1();
          f->WriteRaw((Alloc<Tuple2<BigStr*, int>>(s, num_chars)));
        }
        else {
          f->write(str28);
          this->PrintNode(val, f, ((indent + INDENT) + INDENT));
        }
      }
      f->write(str29);
    }
    f->write(str_concat(ind, node->right));
  }
}

void _PrettyPrinter::PrintNode(hnode_asdl::hnode_t* node, format::ColorOutput* f, int indent) {
  BigStr* ind = nullptr;
  format::ColorOutput* single_f = nullptr;
  BigStr* s = nullptr;
  int num_chars;
  hnode_asdl::hnode_t* UP_node = nullptr;
  int tag;
  StackRoot _root0(&node);
  StackRoot _root1(&f);
  StackRoot _root2(&ind);
  StackRoot _root3(&single_f);
  StackRoot _root4(&s);
  StackRoot _root5(&UP_node);

  ind = str_repeat(str30, indent);
  single_f = f->NewTempBuffer();
  single_f->write(ind);
  if (_TrySingleLine(node, single_f, (this->max_col - indent))) {
    Tuple2<BigStr*, int> tup4 = single_f->GetRaw();
    s = tup4.at0();
    num_chars = tup4.at1();
    f->WriteRaw((Alloc<Tuple2<BigStr*, int>>(s, num_chars)));
    return ;
  }
  UP_node = node;
  tag = node->tag();
  if (tag == hnode_e::Leaf) {
    hnode::Leaf* node = static_cast<hnode::Leaf*>(UP_node);
    f->PushColor(node->color);
    f->write(j8_lite::EncodeString(node->s, true));
    f->PopColor();
  }
  else {
    if (tag == hnode_e::External) {
      hnode::External* node = static_cast<hnode::External*>(UP_node);
      f->PushColor(color_e::External);
      // if not PYTHON
      {
        f->write(str31);
      }
      // endif MYCPP
      f->PopColor();
    }
    else {
      if (tag == hnode_e::Record) {
        hnode::Record* node = static_cast<hnode::Record*>(UP_node);
        this->_PrintRecord(node, f, indent);
      }
      else {
        if (tag == hnode_e::AlreadySeen) {
          hnode::AlreadySeen* node = static_cast<hnode::AlreadySeen*>(UP_node);
          f->write(StrFormat("...0x%s", mylib::hex_lower(node->heap_id)));
        }
        else {
          assert(0);  // AssertionError
        }
      }
    }
  }
}

bool _TrySingleLineObj(hnode::Record* node, format::ColorOutput* f, int max_chars) {
  int i;
  StackRoot _root0(&node);
  StackRoot _root1(&f);

  f->write(node->left);
  if (node->abbrev) {
    if (len(node->node_type)) {
      f->PushColor(color_e::TypeName);
      f->write(node->node_type);
      f->PopColor();
      f->write(str33);
    }
    i = 0;
    for (ListIter<hnode_asdl::hnode_t*> it(node->unnamed_fields); !it.Done(); it.Next(), ++i) {
      hnode_asdl::hnode_t* val = it.Value();
      StackRoot _for(&val    );
      if (i != 0) {
        f->write(str34);
      }
      if (!_TrySingleLine(val, f, max_chars)) {
        return false;
      }
    }
  }
  else {
    f->PushColor(color_e::TypeName);
    f->write(node->node_type);
    f->PopColor();
    for (ListIter<hnode_asdl::Field*> it(node->fields); !it.Done(); it.Next()) {
      hnode_asdl::Field* field = it.Value();
      StackRoot _for(&field    );
      f->write(StrFormat(" %s:", field->name));
      if (!_TrySingleLine(field->val, f, max_chars)) {
        return false;
      }
    }
  }
  f->write(node->right);
  return true;
}

bool _TrySingleLine(hnode_asdl::hnode_t* node, format::ColorOutput* f, int max_chars) {
  hnode_asdl::hnode_t* UP_node = nullptr;
  int tag;
  int i;
  int num_chars_so_far;
  StackRoot _root0(&node);
  StackRoot _root1(&f);
  StackRoot _root2(&UP_node);

  UP_node = node;
  tag = node->tag();
  if (tag == hnode_e::Leaf) {
    hnode::Leaf* node = static_cast<hnode::Leaf*>(UP_node);
    f->PushColor(node->color);
    f->write(j8_lite::EncodeString(node->s, true));
    f->PopColor();
  }
  else {
    if (tag == hnode_e::External) {
      hnode::External* node = static_cast<hnode::External*>(UP_node);
      f->PushColor(color_e::External);
      // if not PYTHON
      {
        f->write(str36);
      }
      // endif MYCPP
      f->PopColor();
    }
    else {
      if (tag == hnode_e::Array) {
        hnode::Array* node = static_cast<hnode::Array*>(UP_node);
        f->write(str37);
        i = 0;
        for (ListIter<hnode_asdl::hnode_t*> it(node->children); !it.Done(); it.Next(), ++i) {
          hnode_asdl::hnode_t* item = it.Value();
          StackRoot _for(&item        );
          if (i != 0) {
            f->write(str38);
          }
          if (!_TrySingleLine(item, f, max_chars)) {
            return false;
          }
        }
        f->write(str39);
      }
      else {
        if (tag == hnode_e::Record) {
          hnode::Record* node = static_cast<hnode::Record*>(UP_node);
          return _TrySingleLineObj(node, f, max_chars);
        }
        else {
          if (tag == hnode_e::AlreadySeen) {
            hnode::AlreadySeen* node = static_cast<hnode::AlreadySeen*>(UP_node);
            f->write(StrFormat("...0x%s", mylib::hex_lower(node->heap_id)));
          }
          else {
            assert(0);  // AssertionError
          }
        }
      }
    }
  }
  num_chars_so_far = f->NumChars();
  if (num_chars_so_far > max_chars) {
    return false;
  }
  return true;
}

void PrintTree(hnode_asdl::hnode_t* node, format::ColorOutput* f) {
  format::_PrettyPrinter* pp = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&f);
  StackRoot _root2(&pp);

  pp = Alloc<_PrettyPrinter>(100);
  pp->PrintNode(node, f, 0);
}

void PrintTree2(hnode_asdl::hnode_t* node, format::ColorOutput* f) {
  pretty_asdl::MeasuredDoc* doc = nullptr;
  pretty::PrettyPrinter* printer = nullptr;
  mylib::BufWriter* buf = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&f);
  StackRoot _root2(&doc);
  StackRoot _root3(&printer);
  StackRoot _root4(&buf);

  doc = pretty::AsciiText(str41);
  printer = Alloc<pretty::PrettyPrinter>(20);
  buf = Alloc<mylib::BufWriter>();
  printer->PrintDoc(doc, buf);
  f->write(buf->getvalue());
  f->write(str42);
}

}  // define namespace format

namespace j8_lite {  // define


BigStr* EncodeString(BigStr* s, bool unquoted_ok) {
  StackRoot _root0(&s);

  if ((unquoted_ok and fastfunc::CanOmitQuotes(s))) {
    return s;
  }
  return fastfunc::J8EncodeString(s, 1);
}

BigStr* YshEncodeString(BigStr* s) {
  StackRoot _root0(&s);

  return fastfunc::ShellEncodeString(s, 1);
}

BigStr* MaybeShellEncode(BigStr* s) {
  StackRoot _root0(&s);

  if (fastfunc::CanOmitQuotes(s)) {
    return s;
  }
  return fastfunc::ShellEncodeString(s, 0);
}

BigStr* ShellEncode(BigStr* s) {
  StackRoot _root0(&s);

  return fastfunc::ShellEncodeString(s, 0);
}

BigStr* YshEncode(BigStr* s, bool unquoted_ok) {
  StackRoot _root0(&s);

  if ((unquoted_ok and fastfunc::CanOmitQuotes(s))) {
    return s;
  }
  return fastfunc::ShellEncodeString(s, 1);
}

}  // define namespace j8_lite

namespace ansi {  // define

BigStr* RESET = str43;
BigStr* BOLD = str44;
BigStr* UNDERLINE = str45;
BigStr* REVERSE = str46;
BigStr* RED = str47;
BigStr* GREEN = str48;
BigStr* YELLOW = str49;
BigStr* BLUE = str50;
BigStr* MAGENTA = str51;
BigStr* CYAN = str52;
BigStr* WHITE = str53;

}  // define namespace ansi

namespace pretty {  // define

using pretty_asdl::doc;
using pretty_asdl::doc_e;
using pretty_asdl::DocFragment;
using pretty_asdl::Measure;
using pretty_asdl::MeasuredDoc;
using mylib::BufWriter;

pretty_asdl::Measure* _EmptyMeasure() {
  return Alloc<Measure>(0, -1);
}

pretty_asdl::Measure* _FlattenMeasure(pretty_asdl::Measure* measure) {
  StackRoot _root0(&measure);

  return Alloc<Measure>(measure->flat, -1);
}

pretty_asdl::Measure* _ConcatMeasure(pretty_asdl::Measure* m1, pretty_asdl::Measure* m2) {
  StackRoot _root0(&m1);
  StackRoot _root1(&m2);

  if (m1->nonflat != -1) {
    return Alloc<Measure>((m1->flat + m2->flat), m1->nonflat);
  }
  else {
    if (m2->nonflat != -1) {
      return Alloc<Measure>((m1->flat + m2->flat), (m1->flat + m2->nonflat));
    }
    else {
      return Alloc<Measure>((m1->flat + m2->flat), -1);
    }
  }
}

int _SuffixLen(pretty_asdl::Measure* measure) {
  StackRoot _root0(&measure);

  if (measure->nonflat != -1) {
    return measure->nonflat;
  }
  else {
    return measure->flat;
  }
}

pretty_asdl::MeasuredDoc* AsciiText(BigStr* string) {
  StackRoot _root0(&string);

  return Alloc<MeasuredDoc>(Alloc<doc::Text>(string), Alloc<Measure>(len(string), -1));
}

pretty_asdl::MeasuredDoc* _Break(BigStr* string) {
  StackRoot _root0(&string);

  return Alloc<MeasuredDoc>(Alloc<doc::Break>(string), Alloc<Measure>(len(string), 0));
}

pretty_asdl::MeasuredDoc* _Indent(int indent, pretty_asdl::MeasuredDoc* mdoc) {
  StackRoot _root0(&mdoc);

  return Alloc<MeasuredDoc>(Alloc<doc::Indent>(indent, mdoc), mdoc->measure);
}

pretty_asdl::MeasuredDoc* _Concat(List<pretty_asdl::MeasuredDoc*>* mdocs) {
  pretty_asdl::Measure* measure = nullptr;
  StackRoot _root0(&mdocs);
  StackRoot _root1(&measure);

  measure = _EmptyMeasure();
  for (ListIter<pretty_asdl::MeasuredDoc*> it(mdocs); !it.Done(); it.Next()) {
    pretty_asdl::MeasuredDoc* mdoc = it.Value();
    StackRoot _for(&mdoc  );
    measure = _ConcatMeasure(measure, mdoc->measure);
  }
  return Alloc<MeasuredDoc>(Alloc<doc::Concat>(mdocs), measure);
}

pretty_asdl::MeasuredDoc* _Group(pretty_asdl::MeasuredDoc* mdoc) {
  StackRoot _root0(&mdoc);

  return Alloc<MeasuredDoc>(Alloc<doc::Group>(mdoc), mdoc->measure);
}

pretty_asdl::MeasuredDoc* _IfFlat(pretty_asdl::MeasuredDoc* flat_mdoc, pretty_asdl::MeasuredDoc* nonflat_mdoc) {
  StackRoot _root0(&flat_mdoc);
  StackRoot _root1(&nonflat_mdoc);

  return Alloc<MeasuredDoc>(Alloc<doc::IfFlat>(flat_mdoc, nonflat_mdoc), Alloc<Measure>(flat_mdoc->measure->flat, nonflat_mdoc->measure->nonflat));
}

pretty_asdl::MeasuredDoc* _Flat(pretty_asdl::MeasuredDoc* mdoc) {
  StackRoot _root0(&mdoc);

  return Alloc<MeasuredDoc>(Alloc<doc::Flat>(mdoc), _FlattenMeasure(mdoc->measure));
}

PrettyPrinter::PrettyPrinter(int max_width) {
  this->max_width = max_width;
}

bool PrettyPrinter::_Fits(int prefix_len, doc::Group* group, pretty_asdl::Measure* suffix_measure) {
  pretty_asdl::Measure* measure = nullptr;
  StackRoot _root0(&group);
  StackRoot _root1(&suffix_measure);
  StackRoot _root2(&measure);

  measure = _ConcatMeasure(_FlattenMeasure(group->mdoc->measure), suffix_measure);
  return (prefix_len + _SuffixLen(measure)) <= this->max_width;
}

void PrettyPrinter::PrintDoc(pretty_asdl::MeasuredDoc* document, mylib::BufWriter* buf) {
  int prefix_len;
  List<pretty_asdl::DocFragment*>* fragments = nullptr;
  pretty_asdl::DocFragment* frag = nullptr;
  doc::Text* text = nullptr;
  BigStr* break_str = nullptr;
  doc::Indent* indented = nullptr;
  doc::Concat* concat = nullptr;
  pretty_asdl::Measure* measure = nullptr;
  doc::Group* group = nullptr;
  bool flat;
  doc::IfFlat* if_flat = nullptr;
  pretty_asdl::MeasuredDoc* subdoc = nullptr;
  doc::Flat* flat_doc = nullptr;
  StackRoot _root0(&document);
  StackRoot _root1(&buf);
  StackRoot _root2(&fragments);
  StackRoot _root3(&frag);
  StackRoot _root4(&text);
  StackRoot _root5(&break_str);
  StackRoot _root6(&indented);
  StackRoot _root7(&concat);
  StackRoot _root8(&measure);
  StackRoot _root9(&group);
  StackRoot _root10(&if_flat);
  StackRoot _root11(&subdoc);
  StackRoot _root12(&flat_doc);

  prefix_len = 0;
  fragments = NewList<pretty_asdl::DocFragment*>(std::initializer_list<pretty_asdl::DocFragment*>{Alloc<DocFragment>(_Group(document), 0, false, _EmptyMeasure())});
  while (len(fragments) > 0) {
    frag = fragments->pop();
    switch (frag->mdoc->doc->tag()) {
      case doc_e::Text: {
        text = static_cast<doc::Text*>(frag->mdoc->doc);
        buf->write(text->string);
        prefix_len += frag->mdoc->measure->flat;
      }
        break;
      case doc_e::Break: {
        if (frag->is_flat) {
          break_str = static_cast<doc::Break*>(frag->mdoc->doc)->string;
          buf->write(break_str);
          prefix_len += frag->mdoc->measure->flat;
        }
        else {
          buf->write(str54);
          buf->write_spaces(frag->indent);
          prefix_len = frag->indent;
        }
      }
        break;
      case doc_e::Indent: {
        indented = static_cast<doc::Indent*>(frag->mdoc->doc);
        fragments->append(Alloc<DocFragment>(indented->mdoc, (frag->indent + indented->indent), frag->is_flat, frag->measure));
      }
        break;
      case doc_e::Concat: {
        concat = static_cast<doc::Concat*>(frag->mdoc->doc);
        measure = frag->measure;
        for (ReverseListIter<pretty_asdl::MeasuredDoc*> it(concat->mdocs); !it.Done(); it.Next()) {
          pretty_asdl::MeasuredDoc* mdoc = it.Value();
          StackRoot _for(&mdoc        );
          fragments->append(Alloc<DocFragment>(mdoc, frag->indent, frag->is_flat, measure));
          measure = _ConcatMeasure(mdoc->measure, measure);
        }
      }
        break;
      case doc_e::Group: {
        group = static_cast<doc::Group*>(frag->mdoc->doc);
        flat = this->_Fits(prefix_len, group, frag->measure);
        fragments->append(Alloc<DocFragment>(group->mdoc, frag->indent, flat, frag->measure));
      }
        break;
      case doc_e::IfFlat: {
        if_flat = static_cast<doc::IfFlat*>(frag->mdoc->doc);
        if (frag->is_flat) {
          subdoc = if_flat->flat_mdoc;
        }
        else {
          subdoc = if_flat->nonflat_mdoc;
        }
        fragments->append(Alloc<DocFragment>(subdoc, frag->indent, frag->is_flat, frag->measure));
      }
        break;
      case doc_e::Flat: {
        flat_doc = static_cast<doc::Flat*>(frag->mdoc->doc);
        fragments->append(Alloc<DocFragment>(flat_doc->mdoc, frag->indent, true, frag->measure));
      }
        break;
    }
  }
}

}  // define namespace pretty

namespace parse {  // define

using expr_asdl::expr;
using expr_asdl::expr_e;
using expr_asdl::expr_t;
using expr_asdl::tok_e;
using expr_asdl::tok_t;
namespace fmt = format;

Lexer::Lexer(BigStr* s) {
  this->s = s;
  this->i = 0;
  this->n = len(s);
}

Tuple2<expr_asdl::tok_t, BigStr*> Lexer::Read() {
  BigStr* tok = nullptr;
  StackRoot _root0(&tok);

  if (this->i >= this->n) {
    return Tuple2<expr_asdl::tok_t, BigStr*>(tok_e::Eof, str55);
  }
  tok = this->s->at(this->i);
  this->i += 1;
  if (tok->isdigit()) {
    return Tuple2<expr_asdl::tok_t, BigStr*>(tok_e::Const, tok);
  }
  if (tok->isalpha()) {
    return Tuple2<expr_asdl::tok_t, BigStr*>(tok_e::Var, tok);
  }
  if (str_contains(str56, tok)) {
    return Tuple2<expr_asdl::tok_t, BigStr*>(tok_e::Op1, tok);
  }
  if (str_contains(str57, tok)) {
    return Tuple2<expr_asdl::tok_t, BigStr*>(tok_e::Op2, tok);
  }
  if (str_contains(str58, tok)) {
    return Tuple2<expr_asdl::tok_t, BigStr*>(tok_e::Paren, tok);
  }
  return Tuple2<expr_asdl::tok_t, BigStr*>(tok_e::Invalid, tok);
}

void Lexer::_MethodCallingOtherMethod() {
  this->Read();
}

ParseError::ParseError(BigStr* msg) {
  this->msg = msg;
}

Parser::Parser(parse::Lexer* lexer) {
  this->lexer = lexer;
  this->tok_type = tok_e::Eof;
  this->tok_val = str59;
}

void Parser::Next() {
  Tuple2<expr_asdl::tok_t, BigStr*> tup0 = this->lexer->Read();
  this->tok_type = tup0.at0();
  this->tok_val = tup0.at1();
}

void Parser::Eat(BigStr* tok_val) {
  StackRoot _root0(&tok_val);

  if (!(str_equals(this->tok_val, tok_val))) {
    throw Alloc<ParseError>(str_concat(str60, tok_val));
  }
  this->Next();
}

expr_asdl::expr_t* Parser::ParseFactor() {
  expr::Var* n1 = nullptr;
  expr::Const* n2 = nullptr;
  expr_asdl::expr_t* n3 = nullptr;
  StackRoot _root0(&n1);
  StackRoot _root1(&n2);
  StackRoot _root2(&n3);

  if (this->tok_type == tok_e::Var) {
    n1 = Alloc<expr::Var>(this->tok_val);
    this->Next();
    return n1;
  }
  if (this->tok_type == tok_e::Const) {
    n2 = Alloc<expr::Const>(to_int(this->tok_val));
    this->Next();
    return n2;
  }
  if (this->tok_type == tok_e::Paren) {
    this->Eat(str61);
    n3 = this->ParseExpr();
    this->Eat(str62);
    return n3;
  }
  throw Alloc<ParseError>(str_concat(str63, this->tok_val));
}

expr_asdl::expr_t* Parser::ParseTerm() {
  expr_asdl::expr_t* node = nullptr;
  BigStr* op = nullptr;
  expr_asdl::expr_t* n2 = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&op);
  StackRoot _root2(&n2);

  node = this->ParseFactor();
  while (this->tok_type == tok_e::Op2) {
    op = this->tok_val;
    this->Next();
    n2 = this->ParseFactor();
    node = Alloc<expr::Binary>(op, node, n2);
  }
  return node;
}

expr_asdl::expr_t* Parser::ParseExpr() {
  expr_asdl::expr_t* node = nullptr;
  BigStr* op = nullptr;
  expr_asdl::expr_t* n2 = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&op);
  StackRoot _root2(&n2);

  node = this->ParseTerm();
  while (this->tok_type == tok_e::Op1) {
    op = this->tok_val;
    this->Next();
    n2 = this->ParseTerm();
    node = Alloc<expr::Binary>(op, node, n2);
  }
  return node;
}

expr_asdl::expr_t* Parser::Parse() {
  this->Next();
  return this->ParseExpr();
}

void TestParse() {
  parse::Lexer* lex = nullptr;
  expr_asdl::tok_t tok_type;
  BigStr* tok_val = nullptr;
  List<BigStr*>* CASES = nullptr;
  parse::Parser* p = nullptr;
  expr_asdl::expr_t* node = nullptr;
  hnode_asdl::hnode_t* htree = nullptr;
  format::AnsiOutput* ast_f = nullptr;
  expr_asdl::expr_t* UP_node = nullptr;
  StackRoot _root0(&lex);
  StackRoot _root1(&tok_val);
  StackRoot _root2(&CASES);
  StackRoot _root3(&p);
  StackRoot _root4(&node);
  StackRoot _root5(&htree);
  StackRoot _root6(&ast_f);
  StackRoot _root7(&UP_node);

  lex = Alloc<Lexer>(str64);
  while (true) {
    Tuple2<expr_asdl::tok_t, BigStr*> tup1 = lex->Read();
    tok_type = tup1.at0();
    tok_val = tup1.at1();
    if (tok_type == tok_e::Eof) {
      break;
    }
    mylib::print_stderr(StrFormat("tok_val %s", tok_val));
  }
  CASES = NewList<BigStr*>(std::initializer_list<BigStr*>{str66, str67, str68, str69, str70, str71, str72, str73, str74, str75, str76, str77, str78});
  for (ListIter<BigStr*> it(CASES); !it.Done(); it.Next()) {
    BigStr* expr_ = it.Value();
    StackRoot _for(&expr_  );
    lex = Alloc<Lexer>(expr_);
    p = Alloc<Parser>(lex);
    mylib::print_stderr(str79);
    mylib::print_stderr(str80);
    mylib::print_stderr(StrFormat("%s =>", expr_));
    node = nullptr;
    try {
      node = p->Parse();
    }
    catch (ParseError* e) {
      mylib::print_stderr(StrFormat("Parse error: %s", e->msg));
      continue;
    }
    htree = node->PrettyTree();
    ast_f = Alloc<fmt::AnsiOutput>(mylib::Stdout());
    fmt::PrintTree(htree, ast_f);
    ast_f->write(str83);
    UP_node = node;
    switch (UP_node->tag()) {
      case expr_e::Const: {
        expr::Const* node = static_cast<expr::Const*>(UP_node);
        mylib::print_stderr(StrFormat("Const %d", node->i));
      }
        break;
      case expr_e::Var: {
        expr::Var* node = static_cast<expr::Var*>(UP_node);
        mylib::print_stderr(StrFormat("Var %s", node->name));
      }
        break;
      default: {
        mylib::print_stderr(str86);
      }
    }
  }
}

void TestCreateNull() {
  expr::Const* c = nullptr;
  expr::Var* v = nullptr;
  expr::Binary* b = nullptr;
  hnode_asdl::hnode_t* htree = nullptr;
  format::AnsiOutput* ast_f = nullptr;
  StackRoot _root0(&c);
  StackRoot _root1(&v);
  StackRoot _root2(&b);
  StackRoot _root3(&htree);
  StackRoot _root4(&ast_f);

  c = expr::Const::CreateNull(true);
  mylib::print_stderr(StrFormat("c.i %d", c->i));
  v = expr::Var::CreateNull(true);
  mylib::print_stderr(StrFormat("v.name %r", v->name));
  b = expr::Binary::CreateNull(true);
  mylib::print_stderr(StrFormat("b.op %r", b->op));
  b->op = str90;
  b->left = c;
  b->right = v;
  htree = b->PrettyTree();
  ast_f = Alloc<fmt::AnsiOutput>(mylib::Stdout());
  fmt::PrintTree(htree, ast_f);
  ast_f->write(str91);
}

void run_tests() {
  TestParse();
  TestCreateNull();
}

void run_benchmarks() {
  int n;
  int result;
  int i;
  parse::Lexer* lex = nullptr;
  parse::Parser* p = nullptr;
  expr_asdl::expr_t* tree = nullptr;
  StackRoot _root0(&lex);
  StackRoot _root1(&p);
  StackRoot _root2(&tree);

  n = 100000;
  result = 0;
  i = 0;
  while (i < n) {
    lex = Alloc<Lexer>(str92);
    p = Alloc<Parser>(lex);
    tree = p->Parse();
    i += 1;
    mylib::MaybeCollect();
  }
  mylib::print_stderr(StrFormat("result = %d", result));
  mylib::print_stderr(StrFormat("iterations = %d", n));
}

}  // define namespace parse

namespace cgi {  // define


BigStr* escape(BigStr* s) {
  StackRoot _root0(&s);

  s = s->replace(str95, str96);
  s = s->replace(str97, str98);
  s = s->replace(str99, str100);
  return s;
}

}  // define namespace cgi

int main(int argc, char **argv) {
  gHeap.Init();

  char* b = getenv("BENCHMARK");
  if (b && strlen(b)) {  // match Python's logic
    fprintf(stderr, "Benchmarking...\n");
    parse::run_benchmarks();
  } else {
    parse::run_tests();
  }

  gHeap.CleanProcessExit();
}