2023-06-26 20:47:31 +00:00
|
|
|
using System;
|
|
|
|
using System.IO;
|
|
|
|
using Finn.AST;
|
|
|
|
|
|
|
|
namespace Finn;
|
|
|
|
|
|
|
|
class ASTPrinter : IVisitor<string>
|
|
|
|
{
|
2023-06-28 18:12:14 +00:00
|
|
|
public string print(Expr expr)
|
2023-06-26 20:47:31 +00:00
|
|
|
{
|
|
|
|
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() ?? "";
|
|
|
|
}
|
|
|
|
|
2023-07-01 06:12:02 +00:00
|
|
|
private string formatName(Name name)
|
|
|
|
{
|
|
|
|
if (name.Quoted) return $"@\"{name.Value}\"";
|
|
|
|
return name.Value;
|
|
|
|
}
|
|
|
|
|
|
|
|
public string visitIdentifierExpr(Identifier expr)
|
|
|
|
{
|
|
|
|
return formatName(expr.Value);
|
|
|
|
}
|
|
|
|
|
2023-06-26 20:47:31 +00:00
|
|
|
public string visitUnaryExpr(Unary expr)
|
|
|
|
{
|
|
|
|
return parenthesize(expr.Op.lexeme, expr.Right);
|
|
|
|
}
|
2023-06-28 22:26:08 +00:00
|
|
|
|
|
|
|
public string visitIfExpr(If expr)
|
|
|
|
{
|
|
|
|
return parenthesize("if", expr.Condition, expr.Then, expr.Else);
|
|
|
|
}
|
2023-06-28 23:18:31 +00:00
|
|
|
|
|
|
|
public string visitSequenceExpr(Sequence expr)
|
|
|
|
{
|
|
|
|
return parenthesize("seq", expr.Left, expr.Right);
|
|
|
|
}
|
2023-07-01 06:12:02 +00:00
|
|
|
|
|
|
|
public string visitSelectorExpr(Selector expr)
|
|
|
|
{
|
|
|
|
return parenthesize(".", expr.Left, new Identifier { Value = expr.FieldName });
|
|
|
|
}
|
2023-07-02 05:13:24 +00:00
|
|
|
|
|
|
|
public string visitListExpr(List expr)
|
|
|
|
{
|
|
|
|
return parenthesize("list", expr.Elements);
|
|
|
|
}
|
2023-07-02 05:30:24 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2023-07-02 17:38:48 +00:00
|
|
|
|
|
|
|
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(')');
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2023-07-02 17:46:18 +00:00
|
|
|
|
|
|
|
public string visitIndexerExpr(Indexer expr)
|
|
|
|
{
|
|
|
|
return parenthesize("index", expr.Left, expr.Index);
|
|
|
|
}
|
2023-06-26 20:47:31 +00:00
|
|
|
}
|