Sawmill icon indicating copy to clipboard operation
Sawmill copied to clipboard

Using Sawmill with multi-category AST?

Open declard opened this issue 1 year ago • 2 comments

I have an AST with multiple categories of the nodes: statements (Stmt), expressions (Expr), patterns (Pat). There are also some less important subcategories.

Stmt may contain Exprs and Pats. Expr may contain Stmts, Pats and Exprs. Pat may contain Pats.

All of them have a common root type SyntaxNode.

Example types:

public class LambdaExpr : Expr
{
    public required List<Pat> Params { get; init; }
    public required Expr Body { get; init; }
}

public class CaseOfExpr : Expr
{
    public required Expr Target { get; init; }
    public required List<CaseStmt> Cases { get; init; }
}

public class AndPat : Pat
{
    public required Pat Left { get; init; }
    public required Pat Right { get; init; }
}

I assume it's impossible to use Sawmill for rewriting, so is the only option for me to have

public SyntaxTree SetChildren(ReadOnlySpan<SyntaxTree> newChildren) => throw new InvalidOperationException();

in the root class and restrict my usage to queries?

declard avatar Nov 13 '24 18:11 declard

Yes this is a well-known (to me, at least!) shortcoming of the single-type-param design of IRewritable.

You can do it type-unsafely by implementing IRewritable on your base SyntaxNode abstract class and downcasting in the concrete nodes:

public class AndPat : Pat
{
    public void SetChildren(ReadOnlySpan<SyntaxNode> children)
        => new AndPat(
            (Pat)children[0],
            (Pat)children[1]
        );
}

but this means you have to be careful never to (eg) replace a Pat with an Expr in your rewriter functions.

To do it type-safely you need something like a two-parameter version of IRewritable and/or the second half of the paper. C# lacks the type-driven automation to make that ergonomic. (These days one might be able to do something with source generators but I haven't tried.)

benjamin-hodgson avatar Nov 16 '24 16:11 benjamin-hodgson

Oh yes, the optics is surely not something to be used in C#, at least not with its current feature set

Are there any plans on read/write interface segregation by any chance? Just hate throwing those exceptions instead of having an implemented method. Liskov, you know :D

declard avatar Nov 18 '24 15:11 declard