finn-lang/ASTPrinter.cs

129 lines
2.4 KiB
C#

using System;
using System.IO;
using Finn.AST;
namespace Finn;
class ASTPrinter : IVisitor<string>
{
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(')');
}
}
}
}