using System;
using System.Collections;
using System.IO;
using System.Diagnostics;
using System.Reflection;

public class source {
     public static compilation visit(compilation ast, TextWriter w, string[] args, MessageWriter msg) {
        if (msg.Count == 0)
            new source(w).visit((AST)ast);
        return ast;
    }

    const int topprec = 16;
    public TextWriter wr;
    public source(TextWriter w) { wr = w; }

    public static string ToString(AST ast) {
        source src = new source(new StringWriter());
        src.visit(ast);
        string result = ((StringWriter)src.wr).ToString();
        src.wr.Close();
        return result;
    }

    virtual public void accessor_declaration(accessor_declaration ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        EmitModifiers(ast.mods, indent, " ");
        if (ast.body != null) {
            Write("{0}", ast.id.str);
            statement(ast.body, indent + 1);
        } else
            WriteLine("{0};", ast.id.str);
    }
    virtual public void alias_directive(alias_directive ast, int indent) {
        Write("using {0} = ", indent, ast.id.str);
        visit(ast.name);
        WriteLine("");
    }
    virtual public void anonymous_method_expression(anonymous_method_expression ast, int indent) {
        Write("delegate ");
        if (ast.formals.Count > 0) {
            EmitParameters(ast.formals, null);
            Write(" ");
        }
        Write("{{");
        foreach (statement s in ((block_statement)ast.block).stmts) {
            Write(" ");
            visit(s);
        }
        Write(" }}");
    }
    virtual public void arglist_parameter(arglist_parameter ast, int indent) {
        Write("__arglist", indent);
    }
    virtual public void array_creation_expression1(array_creation_expression1 ast, int parent) {
        Write("new ");
        visit(ast.ty);
        Write("[");
        EmitexpressionList(ast.exprs);
        Write("]");
        if (ast.ranks != null)
            foreach (int rank in ast.ranks)
                Write("[{0}]", "".PadRight(rank, ','));
        if (ast.init != null)
            visit(ast.init);
    }
    virtual public void array_creation_expression2(array_creation_expression2 ast, int parent) {
        Write("new ");
        visit(ast.ty);
        Write(" ");
        visit(ast.init);
    }
    virtual public void array_initializer(array_initializer ast, int indent) {
        Write("{{ ");
        for (int i = 0; i < ast.a.Count; i++) {
            if (i > 0)
                Write(", ");
            visit(ast.a[i]);
        }
        Write(" }}");
    }
    virtual public void array_type(array_type ast, int indent) {
        visit(ast.ty, indent);
        Write("[{0}]", "".PadRight(ast.rank_specifier, ','));
    }
    virtual public void as_expression(as_expression ast, int parent) {
        int myprec = prec("as");
        if (myprec <= parent)
            parenexpr(ast, 0);
        else {
            visit(ast.expr, myprec);
            Write(" as ");
            visit(ast.ty);
        }
    }
    virtual public void assignment_expression(assignment_expression ast, int parent) {
        int myprec = prec("=");
        if (myprec <= parent)
            parenexpr(ast);
        else {
            visit(ast.e1, myprec);
            Write(" = ");
            visit(ast.e2, myprec);
        }
    }
    virtual public void attribute(attribute ast, int indent) {
        visit(ast.name);
        if (ast.arguments != null) {
            Write("(");
            EmitargumentList(ast.arguments.args);
            if (ast.arguments.namedargs.Count > 0) {
                if (ast.arguments.args.Count > 0)
                    Write(", ");
                for (int i = 0; i < ast.arguments.namedargs.Count; i++) {
                    if (i > 0)
                        Write(", ");
                    Write("{0}=", ast.arguments.namedargs[i].id.str);
                    visit(ast.arguments.namedargs[i].expr);
                }
            }
            Write(")");
        }
    }
    virtual public void attribute_section(attribute_section ast, int indent) {
        Write("[", indent);
        if (ast.target != null)
            Write("{0}: ", ast.target.str);
        foreach (attribute a in ast.attributes)
            visit(a);
        WriteLine("]");
    }
    virtual public void base_access(base_access ast, int parent) {
        Write("base");
    }
    virtual public void base_initializer(base_initializer ast, int indent) {
        if (ast.args.Count > 0) {
            Write(" : base");
            EmitargumentList(ast.args);
        }
    }
    virtual public void binary_declarator(binary_declarator ast, int indent) {
        visit(ast.ty, indent);
        Write(" operator {0}(", ast.op.str);
        visit(ast.t1);
        Write(" {0}, ", ast.id1.str);
        visit(ast.t2);
        Write(" {0})", ast.id2.str);
    }
    virtual public void binary_expression(binary_expression ast, int parent) {
        int myprec = prec(ast.op);
        if (myprec <= parent)
            parenexpr(ast);
        else {
            visit(ast.e1, myprec);
            Write(" {0} ", ast.op.str);
            visit(ast.e2, myprec);
        }
    }
    virtual public void block(block_statement ast, int indent) {
        WriteLine("{{");
        foreach (statement s in ast.stmts)
            visit(s, indent);
        Write("}}", indent - 1);
    }
    virtual public void block_statement(block_statement ast, int indent) {
        block(ast, indent);
        if (indent > 0)
            WriteLine("");
    }
    virtual public void bool_type(type ast, int indent) {
        Write("bool", indent);
    }
    virtual public void break_statement(break_statement ast, int indent) {
        Write("break", indent);
        Semicolon(indent);
    }
    virtual public void byte_type(type ast, int indent) {
        Write("byte", indent);
    }
    virtual public void cast_expression(cast_expression ast, int parent) {
        int myprec = prec("cast");
        if (myprec <= parent)
            parenexpr(ast);
        else {
            Write("(");
            visit(ast.ty);
            Write(")");
            visit(ast.expr, myprec);
        }
    }
    virtual public void catch_clause(catch_clause ast, int indent) {
        Write("catch (", indent);
        visit(ast.ty);
        if (ast.id != null)
            Write(" {0}", ast.id.str);
        Write(")");
        statement(ast.block, indent + 1);
    }
    virtual public void catch_clauses(catch_clauses ast, int indent) {
        foreach (catch_clause c in ast.specifics)
            visit(c, indent);
        if (ast.general != null) {
            WriteLine("catch", indent);
            visit(ast.general, indent + 1);
        }
    }
    virtual public void char_type(type ast, int indent) {
        Write("char", indent);
    }
    virtual public void checked_expression(checked_expression ast, int parent) {
        Write("checked (");
        visit(ast.expr, topprec);
        Write(")");
    }
    virtual public void checked_statement(checked_statement ast, int indent) {
        Write("checked", indent);
        statement(ast.stmt, indent + 1);
    }
    virtual public void class_declaration(class_declaration ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        EmitModifiers(ast.mods, indent, " ");
        Write("class {0}", ast.id.str);
        EmitTypeList(ast.typeparams);
        if (ast.bases.Count > 0) {
            Write(": ");
            visit(ast.bases[(0)]);
            for (int i = 1; i < ast.bases.Count; i++) {
                Write(", ");
                visit(ast.bases[(i)]);
            }
        }
        EmitTypeConstraints(ast.constraints, indent + 1);
        WriteLine(" {{");
        foreach (declaration d in ast.body)
            visit(d, indent + 1);
        WriteLine("}}", indent);
    }
    protected void compilation(compilation ast, int indent) {
        foreach (compilation_unit x in ast.inputs)
            compilation_unit(x, indent);
    }
    virtual public void compilation_unit(compilation_unit ast, int indent) {
        foreach (using_directive u in ast.using_directives)
            visit(u, indent);
        EmitattributeSectionList(ast.attributes, indent);
        foreach (declaration d in ast.declarations) {
            WriteLine("");
            visit(d, indent);
        }
    }
    virtual public void compound_assignment_expression(compound_assignment_expression ast, int parent) {
        int myprec = prec("=");
        if (myprec <= parent)
            parenexpr(ast);
        else {
            visit(ast.e1, myprec);
            Write(" {0} ", ast.op.str);
            visit(ast.e2, myprec);
        }
    }
    virtual public void cond_expression(cond_expression ast, int parent) {
        int myprec = prec("?:");
        if (myprec <= parent)
            parenexpr(ast);
        else {
            visit(ast.cond, myprec);
            Write(" ? ");
            visit(ast.success, myprec);
            Write(" : ");
            visit(ast.failure, myprec);
        }
    }
    virtual public void const_declarator(const_declarator ast, int indent) {
        Write(" = ");
        visit(ast.expr);
    }
    virtual public void const_statement(const_statement ast, int indent) {
        Write("const ", indent);
        EmitdeclaratorList(ast.ty, ast.consts);
        Semicolon(indent);
    }
    virtual public void constant_declaration(constant_declaration ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        EmitModifiers(ast.mods, indent, " ");
        Write("const ");
        EmitdeclaratorList(ast.ty, ast.decls);
        WriteLine(";");
    }
    virtual public void constructor_constraint(constructor_constraint ast, int indent) {
        Write("new ()");
    }
    virtual public void constructor_declaration(constructor_declaration ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        EmitModifiers(ast.mods, indent, " ");
        Write("{0}", ast.decl.id.str);
        EmitParameters(ast.decl.f.fixeds, ast.decl.f.param);
        if (ast.decl.init != null)
            visit(ast.decl.init);
        if (ast.block != null)
            statement(ast.block, indent + 1);
        else
            WriteLine(";");
    }
    virtual public void continue_statement(continue_statement ast, int indent) {
        Write("continue", indent);
        Semicolon(indent);
    }
    virtual public void decimal_type(type ast, int indent) {
        Write("decimal", indent);
    }
    virtual public void delegate_declaration(delegate_declaration ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        EmitModifiers(ast.mods, indent, " ");
        Write("delegate ");
        visit(ast.ty);
        Write(" {0}", ast.id.str);
        EmitTypeList(ast.typeparams);
        EmitParameters(ast.f.fixeds, ast.f.param);
        EmitTypeConstraints(ast.constraints, indent + 1);
        WriteLine(";");
    }
    virtual public void destructor_declaration(destructor_declaration ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        EmitModifiers(ast.mods, indent, " ");
        Write(" ~{0}()", ast.id.str);
        if (ast.block != null) {
            WriteLine("");
            visit(ast.block, indent + 1);
        } else
            WriteLine(";");
    }
    virtual public void do_statement(do_statement ast, int indent) {
        Write("do", indent);
        statement(ast.body, indent + 1, false);
        if (ast.body is block_statement)
            Write(" while (");
        else
            Write("while (", indent);
        visit(ast.expr);
        Write(")");
        Semicolon(indent);
    }
    virtual public void double_type(type ast, int indent) {
        Write("double", indent);
    }
    virtual public void element_access(element_access ast, int parent) {
        visit(ast.expr, topprec);
        EmitargumentList(ast.exprs, "[", "]");
    }
    protected void EmitargumentList(argumentList args) {
        EmitargumentList(args, "(", ")");
    }
    protected void EmitargumentList(argumentList args, string lparen, string rparen) {
        Write(lparen);
        for (int i = 0; i < args.Count; i++) {
            if (i > 0)
                Write(", ");
            if (args[i].kind != null)
                Write("{0} ", args[i].kind.str);
            visit(args[i].expr);
        }
        Write(rparen);
    }
    protected void EmitattributeSectionList(attribute_sectionList attrs, int indent) {
        foreach (attribute_section s in attrs)
            attribute_section(s, indent);
    }
    protected void EmitdeclaratorList(type ty, declaratorList decls) {
        visit(ty);
        Write(" ");
        for (int i = 0; i < decls.Count; i++) {
            if (i > 0)
                Write(", ");
            Write(decls[i].id.str);
            visit(decls[i]);
        }
    }
    protected void EmitexpressionList(expressionList exprs) {
        for (int i = 0; i < exprs.Count; i++) {
            if (i > 0)
                Write(", ");
            visit(exprs[i]);
        }
    }
    protected void EmitindexerParameters(parameterList fixeds, parameter param) {
        Write("this[");
        for (int i = 0; i < fixeds.Count; i++) {
            if (i > 0)
                Write(", ");
            visit(fixeds[i]);
        }
        if (param != null) {
            if (fixeds.Count > 0)
                Write(", ");
            visit(param);
        }
        Write("]");
    }
    protected void EmitModifiers(InputElementList mods, int indent, string suffix) {
        Indent(indent);
        if (mods.Count > 0) {
            bool partial = false;
            int n = 0;
            foreach (InputElement e in mods)
                if (e.str == "partial")
                    partial = true;
                else
                    Write(n++ > 0 ? " {0}" : "{0}", e.str);
            if (partial)
                Write(n++ > 0 ? " partial" : "partial");
            Write("{0}", suffix);
        }
    }
    protected void EmitParameters(parameterList fixeds, parameter param) {
        Write("(");
        for (int i = 0; i < fixeds.Count; i++) {
            if (i > 0)
                Write(", ");
            visit(fixeds[i]);
        }
        if (param != null) {
            if (fixeds.Count > 0)
                Write(", ");
            visit(param);
        }
        Write(")");
    }
    protected void EmitTypeConstraints(IList constraints, int indent) {
        for (int i = 0; i < constraints.Count; i++) {
            WriteLine("");
            Indent(indent);
            visit((AST)constraints[i]);
        }
    }
    protected void EmitTypeList(IList types) {
        if (types != null && types.Count > 0) {
            Write("<");
            for (int i = 0; i < types.Count; i++) {
                if (i > 0)
                    Write(", ");
                visit((AST)types[i]);
            }
            Write(">");
        }
    }
    virtual public void empty_statement(empty_statement ast, int indent) {
        Semicolon(indent);
    }
    virtual public void enum_declaration(enum_declaration ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        EmitModifiers(ast.mods, indent, " ");
        Write("enum {0} ", ast.id.str);
        if (ast.ty != null) {
            Write(": ");
            visit(ast.ty);
        }
        WriteLine(" {{");
        foreach (enum_member_declaration d in ast.body) {
            EmitattributeSectionList(d.attrs, indent + 1);
            Write("{0}", indent + 1, d.id.str);
            if (d.expr != null) {
                Write("=");
                visit(d.expr);
            }
            WriteLine(",");
        }
        WriteLine("}};", indent);
    }
    virtual public void event_declaration1(event_declaration1 ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        EmitModifiers(ast.mods, indent, " ");
        Write("event ");
        EmitdeclaratorList(ast.ty, ast.decls);
        WriteLine(";");
    }
    virtual public void event_declaration2(event_declaration2 ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        EmitModifiers(ast.mods, indent, " ");
        Write("event ");
        visit(ast.ty);
        Write(" ");
        visit(ast.name);
        WriteLine(" {{");
        foreach (event_accessor a in ast.accessors) {
            EmitattributeSectionList(a.attrs, indent + 1);
            Write("{0}", indent + 1, a.id.str);
            statement(a.block, indent + 2);
        }
        WriteLine("}}", indent);
    }
    virtual public void event_declarator(event_declarator ast, int indent) {
        if (ast.init != null) {
            Write(" = ");
            visit(ast.init);
        }
    }
    virtual public void explicit_declarator(explicit_declarator ast, int indent) {
        Write("explicit operator ", indent);
        visit(ast.ty);
        Write("(");
        visit(ast.t1);
        Write(" {0})", ast.id1.str);
    }
    virtual public void expr_access(expr_access ast, int parent) {
        visit(ast.expr, topprec);
        Write(".{0}", ast.id.str);
        EmitTypeList(ast.typeargs);
    }
    virtual public void expr_initializer(expr_initializer ast, int indent) {
        visit(ast.expr);
    }
    virtual public void expression_statement(expression_statement ast, int indent) {
        Indent(indent);
        visit(ast.expr);
        Semicolon(indent);
    }
    virtual public void field_declaration(field_declaration ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        EmitModifiers(ast.mods, indent, " ");
        EmitdeclaratorList(ast.ty, ast.decls);
        WriteLine(";");
    }
    virtual public void field_declarator(field_declarator ast, int indent) {
        if (ast.init != null) {
            Write(" = ");
            visit(ast.init);
        }
    }
    virtual public void fixed_declarator(fixed_declarator ast, int indent) {
        Write(" = ", indent);
        visit(ast.expr);
    }
    virtual public void fixed_parameter(fixed_parameter ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        if (ast.mod != null) {
            Write("{0} ", indent, ast.mod.str);
            visit(ast.ty);
        } else
            visit(ast.ty, indent);
        Write(" {0}", ast.id.str);
    }
    virtual public void fixed_statement(fixed_statement ast, int indent) {
        Write("fixed (", indent);
        EmitdeclaratorList(ast.ty, ast.declarators);
        Write(")");
        statement(ast.body, indent + 1);
    }
    virtual public void float_type(type ast, int indent) {
        Write("float", indent);
    }
    virtual public void for_decl(for_decl ast, int indent) {
        EmitdeclaratorList(ast.decl.ty, ast.decl.vars);
    }
    virtual public void for_list(for_list ast, int indent) {
        EmitexpressionList(ast.exprs);
    }
    virtual public void for_statement(for_statement ast, int indent) {
        Write("for (", indent);
        if (ast.init != null)
            visit(ast.init);
        Write("; ");
        if (ast.cond != null)
            visit(ast.cond);
        Write("; ");
        EmitexpressionList(ast.iterators);
        Write(")");
        statement(ast.body, indent + 1);
    }
    virtual public void foreach_statement(foreach_statement ast, int indent) {
        Write("foreach (", indent);
        visit(ast.ty);
        Write(" {0} in ", ast.id.str);
        visit(ast.expr);
        Write(")");
        statement(ast.body, indent + 1);
    }
    virtual public void generic_interface_method_declaration(generic_interface_method_declaration ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        EmitModifiers(ast.mods, indent, " ");
        visit(ast.ty);
        Write(" {0} ", ast.id.str);
        EmitTypeList(ast.typeparams);
        EmitParameters(ast.f.fixeds, ast.f.param);
        EmitTypeConstraints(ast.constraints, indent + 1);
        WriteLine(";");
    }
    virtual public void generic_method_declaration(generic_method_declaration ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        EmitModifiers(ast.mods, indent, " ");
        visit(ast.ty);
        Write(" ");
        visit(ast.name);
        EmitTypeList(ast.typeparams);
        EmitParameters(ast.parms.fixeds, ast.parms.param);
        EmitTypeConstraints(ast.constraints, indent + 1);
        if (ast.body != null)
            statement(ast.body, indent + 1);
        else
            WriteLine(";");
    }
    virtual public void goto_case_statement(goto_case_statement ast, int indent) {
        Write("goto case ", indent);
        visit(ast.expr);
        Semicolon(indent);
    }
    virtual public void goto_default_statement(goto_default_statement ast, int indent) {
        Write("goto default", indent);
        Semicolon(indent);
    }
    virtual public void goto_statement(goto_statement ast, int indent) {
        Write("goto {0}", indent, ast.id.str);
        Semicolon(indent);
    }
    virtual public void if_statement(if_statement ast, int indent) {
        Indent(indent);
        ifstmt(ast, indent);
    }
    virtual public void ifstmt(if_statement ast, int indent) {
        Write("if (");
        visit(ast.expr);
        Write(")");
        if (ast.elsepart != null) {
            statement(ast.thenpart, indent + 1, false);
            if (ast.thenpart is block_statement)
                Write(" else");
            else
                Write("else", indent);
            if (ast.elsepart is if_statement) {
                Write(" ");
                ifstmt((if_statement)ast.elsepart, indent);
            } else
                statement(ast.elsepart, indent + 1);
        } else
            statement(ast.thenpart, indent + 1);
    }
    virtual public void implicit_cast_expression(implicit_cast_expression ast, int parent) {
        visit(ast.expr, parent);
    }
    virtual public void implicit_declarator(implicit_declarator ast, int indent) {
        Write("implicit operator ", indent);
        visit(ast.ty);
        Write("(");
        visit(ast.t1);
        Write(" {0})", ast.id1.str);
    }
    protected void Indent(int n) {
        if (n > 0)
            wr.Write("{0}", "".PadRight(n, '\t'));
    }
    virtual public void indexer_declaration(indexer_declaration ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        EmitModifiers(ast.mods, indent, " ");
        visit(ast.i.ty);
        Write(" ");
        if (ast.i.interfacename != null) {
            visit(ast.i.interfacename);
            Write(".");
        }
        EmitindexerParameters(ast.i.f.fixeds, ast.i.f.param);
        WriteLine(" {{", indent);
        foreach (declaration d in ast.accessors)
            visit(d, indent + 1);
        WriteLine("}}", indent);
    }
    virtual public void int_type(type ast, int indent) {
        Write("int", indent);
    }
    virtual public void interface_declaration(interface_declaration ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        EmitModifiers(ast.mods, indent, " ");
        Write("interface {0}", ast.id.str);
        EmitTypeList(ast.typeparams);
        if (ast.interfaces.Count > 0) {
            Write(": ");
            visit(ast.interfaces[0]);
            for (int i = 1; i < ast.interfaces.Count; i++) {
                Write(", ");
                visit(ast.interfaces[i]);
            }
        }
        EmitTypeConstraints(ast.constraints, indent + 1);
        WriteLine(" {{");
        foreach (declaration d in ast.body)
            visit(d, indent + 1);
        WriteLine("}}", indent);
    }
    virtual public void interface_event_declaration(interface_event_declaration ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        EmitModifiers(ast.mods, indent, " ");
        Write("event ");
        visit(ast.ty);
        WriteLine(" {0};", ast.id.str);
    }
    virtual public void interface_indexer_declaration(interface_indexer_declaration ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        EmitModifiers(ast.mods, indent, " ");
        visit(ast.ty);
        Write(" ");
        EmitindexerParameters(ast.f.fixeds, ast.f.param);
        WriteLine(" {{");
        foreach (accessor_declaration a in ast.accessors)
            visit(a, indent + 1);
        WriteLine("}}", indent);
    }
    virtual public void interface_method_declaration(interface_method_declaration ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        EmitModifiers(ast.mods, indent, " ");
        visit(ast.ty);
        Write(" {0}", ast.id.str);
        EmitParameters(ast.f.fixeds, ast.f.param);
        WriteLine(";");
    }
    virtual public void interface_property_declaration(interface_property_declaration ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        EmitModifiers(ast.mods, indent, " ");
        visit(ast.ty);
        Write(" {0} {{", ast.id.str);
        foreach (accessor_declaration a in ast.accessors)
            visit(a, indent + 1);
        WriteLine("}}", indent);
    }
    virtual public void invocation_expression(invocation_expression ast, int parent) {
        visit(ast.expr, topprec);
        EmitargumentList(ast.args);
    }
    virtual public void is_expression(is_expression ast, int parent) {
        int myprec = prec("is");
        if (myprec <= parent)
            parenexpr(ast, 0);
        else {
            visit(ast.expr, myprec);
            Write(" is ");
            visit(ast.ty);
        }
    }
    virtual public void labeled_statement(labeled_statement ast, int indent) {
        WriteLine("{0}:", ast.label.str);
        visit(ast.stmt, indent);
    }
    virtual public void literal(literal ast, int parent) {
        Write("{0}", ast.token.str);
    }
    virtual public void local_expression(local_expression ast, int indent) {
        visit(ast.expr);
    }
    virtual public void local_statement(local_statement ast, int indent) {
        Indent(indent);
        EmitdeclaratorList(ast.ty, ast.vars);
        Semicolon(indent);
    }
    virtual public void lock_statement(lock_statement ast, int indent) {
        Write("lock (", indent);
        visit(ast.expr);
        Write(")");
        statement(ast.body, indent + 1);
    }
    virtual public void long_type(type ast, int indent) {
        Write("long", indent);
    }
    virtual public void member_name(member_name ast, int indent) {
        if (ast.ty != null) {
            visit(ast.ty, indent);
            Write(".{0}", ast.id.str);
        } else
            Write("{0}", indent, ast.id.str);
    }
    virtual public void method_declaration(method_declaration ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        EmitModifiers(ast.mods, indent, " ");
        visit(ast.ty);
        Write(" ");
        visit(ast.name);
        EmitParameters(ast.parms.fixeds, ast.parms.param);
        if (ast.body != null)
            statement(ast.body, indent + 1);
        else
            WriteLine(";");
    }
    virtual public void dotted_name(dotted_name ast, int indent) {
        if (ast.left != null) {
            visit(ast.left);
            Write(".");
        }
        Write("{0}", ast.right.str);
        EmitTypeList(ast.typeargs);
    }
    virtual public void name_type(name_type ast, int indent) {
        Indent(indent);
        visit(ast.name);
    }
    virtual public void namespace_declaration(namespace_declaration ast, int indent) {
        WriteLine("namespace {0} {{", indent, ast.id);
        foreach (using_directive ud in ast.nb.ud)
            visit(ud, indent + 1);
        foreach (declaration d in ast.nb.declarations)
            visit(d, indent + 1);
        WriteLine("}}", indent);
    }
    virtual public void namespace_directive(namespace_directive ast, int indent) {
        WriteLine("using {0};", indent, ast.name);
    }
    virtual public void new_expression(new_expression ast, int parent) {
        Write("new ");
        visit(ast.ty);
        EmitargumentList(ast.args);
    }
    virtual public void object_type(type ast, int indent) {
        Write("object", indent);
    }
    virtual public void operator_declaration(operator_declaration ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        EmitModifiers(ast.mods, indent, " ");
        visit(ast.op);
        if (ast.block != null)
            statement(ast.block, indent + 1);
    }
    virtual public void params_parameter(params_parameter ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        Write("params ", indent);
        visit(ast.ty);
        Write(" {0}", ast.id.str);
    }
    virtual public void parenexpr(expression ast) {
        parenexpr(ast, 0);
    }
    virtual public void parenexpr(expression ast, int parent) {
        Write("(");
        visit(ast, parent);
        Write(")");
    }
    virtual public void pointer_access(pointer_access ast, int parent) {
        visit(ast.expr, topprec);
        Write("->{0}", ast.id.str);
    }
    virtual public void pointer_type(pointer_type ast, int indent) {
        visit(ast.ty, indent);
        Write("*");
    }
    virtual public void post_expression(post_expression ast, int parent) {
        visit(ast.expr, topprec);
        Write("{0}", ast.op.str);
    }
    virtual public void pre_expression(pre_expression ast, int parent) {
        int myprec = prec(ast.op.str + "e");
        if (myprec <= parent)
            parenexpr(ast);
        else {
            Write("{0}", ast.op.str);
            visit(ast.expr, myprec);
        }
    }
    public static int prec(string op) {
        switch (op) {
        case  "=": return 1;
        case "?:": return 2;
        case "||": return 3;
        case "&&": return 4;
        case  "|": return 5;
        case  "^": return 6;
        case  "&": return 7;
        case "==": case "!=": return 8;
        case "is": case "as": case ">=": case "<=": case "<": case ">": return 9;
        case ">>": case "<<": return 10;
        case  "+": case  "-": return 11;
        case  "*": case  "/": case "%": return 12;
        case "cast": return 13;
        case "--e": case "++e": return 14;
        case  "-e": case  "+e": case "*e": case "~e": case "!e": case "&e": return 15;
        default:
            Debug.Assert(false);
            return 0;
        }
    }
    public static int prec(InputElement op) {
        return prec(op.str);
    }
    virtual public void predefined_access(predefined_access ast, int indent) {
        Write("{0}.{1}", ast.predefined.str, ast.id.str);
        EmitTypeList(ast.typeargs);
    }
    virtual public void property_declaration(property_declaration ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        EmitModifiers(ast.mods, indent, " ");
        visit(ast.ty);
        Write(" ");
        visit(ast.name);
        WriteLine(" {{");
        foreach (accessor_declaration d in ast.decls)
            visit(d, indent + 1);
        WriteLine("}}", indent);
    }
    virtual public void qualified_alias_member(qualified_alias_member ast, int indent) {
        Write("{0}::", indent, ast.qualifier.str);
        dotted_name(ast, 0);
    }
    virtual public void qualified_name(qualified_name ast, int indent) {
        Write("{0}::", indent, ast.qualifier.str);
        simple_name(ast, 0);
    }
    virtual public void resource_decl(resource_decl ast, int indent) {
        Indent(indent);
        EmitdeclaratorList(ast.local.ty, ast.local.vars);
    }
    virtual public void resource_expr(resource_expr ast, int indent) {
        visit(ast.expr, indent);
    }
    virtual public void return_statement(return_statement ast, int indent) {
        Write("return", indent);
        if (ast.expr != null) {
            Write(" ");
            visit(ast.expr);
        }
        Semicolon(indent);
    }
    virtual public void sbyte_type(type ast, int indent) {
        Write("sbyte", indent);
    }
    protected void Semicolon(int indent) {
        if (indent > 0)
            WriteLine(";");
        else
            Write(";");
    }
    virtual public void short_type(type ast, int indent) {
        Write("short", indent);
    }
    virtual public void simple_name(simple_name ast, int parent) {
        Write("{0}", ast.id.str);
        EmitTypeList(ast.typeargs);
    }
    virtual public void sizeof_expression(sizeof_expression ast, int parent) {
        Write("sizeof (");
        visit(ast.ty);
        Write(")");
    }
    virtual public void stackalloc_initializer(stackalloc_initializer ast, int indent) {
        Write("stackalloc ", indent);
        visit(ast.ty);
        Write("[");
        visit(ast.expr);
        Write("]");
    }
    virtual public void statement(statement ast, int indent) {
        statement(ast, indent, true);
    }
    virtual public void statement(statement ast, int indent, bool newline) {
        if (ast is block_statement) {
            Write(" ");
            block((block_statement)ast, indent);
            if (newline)
                WriteLine("");
        } else {
            WriteLine("");
            visit(ast, indent);
        }
    }
    virtual public void string_type(type ast, int indent) {
        Write("string", indent);
    }
    virtual public void struct_declaration(struct_declaration ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        EmitModifiers(ast.mods, indent, " ");
        Write("struct {0}", ast.id.str);
        EmitTypeList(ast.typeparams);
        if (ast.interfaces.Count > 0) {
            Write(": ");
            visit(ast.interfaces[0]);
            for (int i = 1; i < ast.interfaces.Count; i++) {
                Write(", ");
                visit(ast.interfaces[i]);
            }
        }
        EmitTypeConstraints(ast.constraints, indent + 1);
        WriteLine(" {{");
        foreach (declaration d in ast.body)
            visit(d, indent + 1);
        WriteLine("}}", indent);
    }
    virtual public void switch_default(switch_default ast, int indent) {
        Write("default:", indent);
    }
    virtual public void switch_expression(switch_expression ast, int indent) {
        Write("case ", indent);
        visit(ast.expr);
        Write(":");
    }
    virtual public void switch_label(switch_label ast, int indent) {
        visit(ast, indent);
        WriteLine("");
    }
    virtual public void switch_statement(switch_statement ast, int indent) {
        Write("switch (", indent);
        visit(ast.expr);
        WriteLine(") {{");
        foreach (switch_section s in ast.sections) {
            foreach (switch_label l in s.labels)
                switch_label(l, indent);
            foreach (statement st in s.stmts)
                visit(st, indent + 1);
        }
        WriteLine("}}", indent);
    }
    virtual public void this_access(this_access ast, int parent) {
        Write("this");
    }
    virtual public void this_initializer(this_initializer ast, int indent) {
        Write(" : this");
        EmitargumentList(ast.args);
    }
    virtual public void throw_statement(throw_statement ast, int indent) {
        Write("throw", indent);
        if (ast.expr != null) {
            Write(" ");
            visit(ast.expr);
        }
        Semicolon(indent);
    }
    virtual public void try_statement(try_statement ast, int indent) {
        Write("try", indent);
        statement(ast.block, indent + 1);
        if (ast.catches != null)
            visit(ast.catches, indent);
        if (ast.finally_block != null) {
            Write("finally", indent);
            statement(ast.finally_block.block, indent + 1);
        }
    }
    virtual public void type_parameter(type_parameter ast, int indent) {
        EmitattributeSectionList(ast.attrs, indent);
        Write("{0}", ast.id.str);
    }
    virtual public void type_parameter_constraints_clause(type_parameter_constraints_clause ast, int indent) {
        Write("where {0}: ", ast.id.str);
        for (int i = 0; i < ast.constraints.Count; i++) {
            if (i > 0)
                Write(", ");
            visit(ast.constraints[i]);
        }
    }
    virtual public void typeof_expression(typeof_expression ast, int parent) {
        Write("typeof (");
        visit(ast.ty);
        Write(")");
    }
    virtual public void uint_type(type ast, int indent) {
        Write("uint", indent);
    }
    virtual public void ulong_type(type ast, int indent) {
        Write("ulong", indent);
    }
    virtual public void unary_declarator(unary_declarator ast, int indent) {
        visit(ast.ty, indent);
        Write(" operator {0}(", ast.op.str);
        visit(ast.t1);
        Write(" {0})", ast.id1.str);
    }
    virtual public void unary_expression(unary_expression ast, int parent) {
        int myprec = prec(ast.op.str + "e");
        if (myprec <= parent)
            parenexpr(ast);
        else {
            Write("{0}", ast.op.str);
            visit(ast.expr, myprec);
        }
    }
    virtual public void unchecked_expression(unchecked_expression ast, int parent) {
        Write("unchecked (");
        visit(ast.expr, topprec);
        Write(")");
    }
    virtual public void unchecked_statement(unchecked_statement ast, int indent) {
        Write("unchecked", indent);
        statement(ast.stmt, indent + 1);
    }
    virtual public void unsafe_statement(unsafe_statement ast, int indent) {
        Write("unsafe", indent);
        statement(ast.block, indent + 1);
    }
    virtual public void ushort_type(type ast, int indent) {
        Write("ushort", indent);
    }
    virtual public void using_statement(using_statement ast, int indent) {
        Write("using (", indent);
        visit(ast.r);
        Write(")");
        statement(ast.body, indent + 1);
    }
    virtual public void var_declarator(var_declarator ast, int indent) {
        if (ast.init != null) {
            Write(" = ");
            visit(ast.init);
        }
    }
    virtual public void visit(AST ast) {
        visit(ast, 0);
    }
    virtual public void visit(AST ast, int indent) {
        const BindingFlags bindingFlags = BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic;
        System.Type t = ast.GetType();
        Debug.Assert(t.IsClass);
        MethodInfo m;
        do {
            m = this.GetType().GetMethod(t.Name, bindingFlags);
            if (m != null)
                break;
            t = t.BaseType;
        } while (t != null);
        if (m != null)
            m.Invoke(this, new object[] { ast, indent });
        else if (indent == 0)
            Write("<{0}>", ast.GetType().Name);
        else
            WriteLine("<{0}>", indent, ast.GetType().Name);
    }
    virtual public void void_pointer_type(void_pointer_type ast, int indent) {
        Write("void*", indent);
    }
    virtual public void void_type(type ast, int indent) {
        Write("void", indent);
    }
    virtual public void while_statement(while_statement ast, int indent) {
        Write("while (", indent);
        visit(ast.expr);
        Write(")");
        statement(ast.body, indent + 1);
    }
    protected void Write(string fmt, int indent, params object[] args) {
        Indent(indent);
        wr.Write(fmt, args);
    }
    protected void Write(string fmt, params object[] args) {
        wr.Write(fmt, args);
    }
    protected void WriteLine(string fmt, int indent, params object[] args) {
        Indent(indent);
        wr.WriteLine(fmt, args);
    }
    protected void WriteLine(string fmt, params object[] args) {
        wr.WriteLine(fmt, args);
    }
    virtual public void yield_return_statement(yield_return_statement ast, int indent) {
        Write("yield return ", indent);
        visit(ast.expr);
        Semicolon(indent);
    }
    virtual public void yield_break_statement(yield_break_statement ast, int indent) {
        Write("yield break", indent);
        Semicolon(indent);
    }
}
