using System; using System.IO; using Finn.AST; namespace Finn; class ASTPrinter : IVisitor { public string print(Expr expr) { return expr.accept(this); } private string parenthesize(string name, params Expr[] exprs) { var w = new StringWriter(); w.Write($"({name}"); foreach (Expr expr in exprs) { w.Write(" "); w.Write(expr.accept(this)); } w.Write(")"); return w.ToString(); } public string visitBinaryExpr(Binary expr) { return parenthesize(expr.Op.lexeme, expr.Left, expr.Right); } public string visitGroupingExpr(Grouping expr) { return parenthesize("group", expr.Expression); } public string visitLiteralExpr(Literal expr) { return expr.Value.ToString() ?? ""; } private string formatName(Name name) { if (name.Quoted) return $"@\"{name.Value}\""; return name.Value; } public string visitIdentifierExpr(Identifier expr) { return formatName(expr.Value); } public string visitUnaryExpr(Unary expr) { return parenthesize(expr.Op.lexeme, expr.Right); } public string visitIfExpr(If expr) { return parenthesize("if", expr.Condition, expr.Then, expr.Else); } public string visitSequenceExpr(Sequence expr) { return parenthesize("seq", expr.Left, expr.Right); } public string visitSelectorExpr(Selector expr) { return parenthesize(".", expr.Left, new Identifier { Value = expr.FieldName }); } public string visitListExpr(List expr) { return parenthesize("list", expr.Elements); } public string visitVariantExpr(Variant expr) { if (expr.Argument == null) { return parenthesize("variant", new Identifier { Value = expr.Tag }); } return parenthesize("variant", new Identifier { Value = expr.Tag }, expr.Argument); } public string visitRecordExpr(Record expr) { StringWriter w = new StringWriter(); w.Write("(record"); writeFields("extend", expr.Extensions); if (expr.Base != null) { w.Write(" (base "); w.Write(print(expr.Base.Value)); writeFields("update", expr.Base.Updates); w.Write(')'); } w.Write(')'); return w.ToString(); void writeFields(string header, Field[] fields) { if (fields.Length != 0) { w.Write($" ({header}"); foreach (var field in fields) { w.Write(' '); var name = formatName(field.Name); if (field.Value == null) { w.Write(name); } else { w.Write(parenthesize(name, field.Value)); } } w.Write(')'); } } } public string visitIndexerExpr(Indexer expr) { return parenthesize("index", expr.Left, expr.Index); } }