Skip to content

Commit

Permalink
Introducing BoundTreeVisitor and BoundTreeWalker (#104)
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisKXu authored Jul 13, 2024
1 parent a59906f commit 884aeac
Show file tree
Hide file tree
Showing 39 changed files with 349 additions and 128 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ internal sealed class BoundTreeVisitorSourceGenerator : IIncrementalGenerator

public void Initialize(IncrementalGeneratorInitializationContext context)
{
context.RegisterPostInitializationOutput(GenerateBoundTreeVisitorDefaultMethods);

var pipeline = context.SyntaxProvider.ForAttributeWithMetadataName(
fullyQualifiedMetadataName: $"{BoundTreeVisitorNamespace}.BoundNodeAttribute",
predicate: static (syntaxNode, _) => syntaxNode is ClassDeclarationSyntax,
Expand All @@ -24,33 +22,20 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
context.RegisterSourceOutput(pipeline, GenerateBoundTreeVisitorMethods);
}

static void GenerateBoundTreeVisitorDefaultMethods(IncrementalGeneratorPostInitializationContext context)
{
var sourceText = SourceText.From($$"""
namespace {{BoundTreeVisitorNamespace}};
[System.CodeDom.Compiler.GeneratedCode("{{nameof(BoundTreeVisitorSourceGenerator)}}", "1.0.0.0")]
internal abstract partial class {{BoundTreeVisitorClassName}}<TArg, TRet>
{
public virtual TRet DefaultVisit(BoundNode node, TArg arg) => default;
}
""", Encoding.UTF8);

context.AddSource($"{BoundTreeVisitorClassName}.g.cs", sourceText);
}

static void GenerateBoundTreeVisitorMethods(SourceProductionContext context, ISymbol symbol)
{
try
{
var className = symbol.Name;
var camelCaseClassName = symbol.CamelCasedName();

var sourceText = SourceText.From($$"""
namespace {{BoundTreeVisitorNamespace}};
internal abstract partial class {{BoundTreeVisitorClassName}}<TArg, TRet>
internal abstract partial class {{BoundTreeVisitorClassName}}
{
public virtual TRet Visit{{className}}({{className}} node, TArg arg) => DefaultVisit(node, arg);
[System.CodeDom.Compiler.GeneratedCode("{{nameof(BoundTreeVisitorSourceGenerator)}}", "1.0.0.0")]
public virtual BoundNode Visit{{className}}({{className}} {{camelCaseClassName}}) => DefaultVisit({{camelCaseClassName}});
}
""", Encoding.UTF8);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public sealed class BoundAssignmentExpressionTests
[InlineData("{ let n = 0; n -= 10; }", "n", BoundAssignmentOperatorKind.SubstractionInline, SpecialType.ClrInt32)]
[InlineData("{ let n = 0; n *= 10; }", "n", BoundAssignmentOperatorKind.MultiplicationInline, SpecialType.ClrInt32)]
[InlineData("{ let n = 0; n /= 10; }", "n", BoundAssignmentOperatorKind.DivisionInline, SpecialType.ClrInt32)]
public void TestBindAssignmentExpressionBasic(
void TestBindAssignmentExpressionBasic(
string input,
string variableName,
BoundAssignmentOperatorKind expectedBoundAssignmentOperatorKind,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public sealed class BoundNodeTests
{
[Theory]
[MemberData(nameof(GetAllSyntaxNodesForTest))]
public void BoundNodeShouldHaveCorrectSyntaxNode(SyntaxNode syntaxNode, BoundNode boundNode)
void BoundNodeShouldHaveCorrectSyntaxNode(SyntaxNode syntaxNode, BoundNode boundNode)
{
boundNode.SyntaxNode.Should().NotBeNull();
boundNode.SyntaxNode.Should().Be(syntaxNode);
Expand All @@ -28,7 +28,7 @@ public void BoundNodeShouldHaveCorrectSyntaxNode(SyntaxNode syntaxNode, BoundNod
[Theory]
[MemberData(nameof(GetAllSyntaxNodesForTest))]
[SuppressMessage("Usage", "xUnit1026:Theory methods should use all of their parameters")]
public void DiagnosticBagShouldNotBeNull(SyntaxNode unused, BoundNode boundNode)
void DiagnosticBagShouldNotBeNull(SyntaxNode unused, BoundNode boundNode)
{
boundNode.DiagnosticBuilder.Should().NotBeNull();
boundNode.GetDiagnostics().Should().NotBeNull();
Expand Down
6 changes: 4 additions & 2 deletions src/Todl.Compiler/CodeAnalysis/Binding/BoundModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace Todl.Compiler.CodeAnalysis.Binding;

public sealed class BoundModule : IDiagnosable
internal sealed class BoundModule : IDiagnosable
{
public IReadOnlyCollection<SyntaxTree> SyntaxTrees { get; private init; }
public BoundEntryPointTypeDefinition EntryPointType { get; private init; }
Expand All @@ -21,9 +21,11 @@ public static BoundModule Create(
var binder = Binder.CreateModuleBinder(clrTypeCache);
var entryPointType = binder.BindEntryPointTypeDefinition(syntaxTrees);

var controlFlowAnalyzer = new ControlFlowAnalyzer();
entryPointType.Accept(controlFlowAnalyzer);

var boundNodeVisitors = new BoundNodeVisitor[]
{
new ControlFlowAnalyzer(),
new ConstantFoldingBoundNodeVisitor(binder.ConstantValueFactory)
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
namespace Todl.Compiler.CodeAnalysis.Binding.BoundTree;

[BoundNode]
public sealed class BoundAssignmentExpression : BoundExpression
internal sealed class BoundAssignmentExpression : BoundExpression
{
public sealed class BoundAssignmentOperator
{
Expand Down Expand Up @@ -45,6 +45,8 @@ internal static BoundAssignmentOperator MatchAssignmentOperator(SyntaxKind synta
public BoundAssignmentOperator Operator { get; internal init; }
public BoundExpression Right { get; internal init; }
public override TypeSymbol ResultType => Right.ResultType;

public override BoundNode Accept(BoundTreeVisitor visitor) => visitor.VisitBoundAssignmentExpression(this);
}

public partial class Binder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ namespace Todl.Compiler.CodeAnalysis.Binding.BoundTree;
using BinaryOperatorIndex = ValueTuple<TypeSymbol, TypeSymbol, SyntaxKind>;

[BoundNode]
public sealed class BoundBinaryExpression : BoundExpression
internal sealed class BoundBinaryExpression : BoundExpression
{
public BoundBinaryOperator Operator { get; internal init; }
public BoundExpression Left { get; internal init; }
public BoundExpression Right { get; internal init; }

public override TypeSymbol ResultType => Operator.ResultType;
public override bool Constant => Left.Constant && Right.Constant;

public override BoundNode Accept(BoundTreeVisitor visitor) => visitor.VisitBoundBinaryExpression(this);
}

public sealed record BoundBinaryOperator(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
namespace Todl.Compiler.CodeAnalysis.Binding.BoundTree;

[BoundNode]
public sealed class BoundBlockStatement : BoundStatement
internal sealed class BoundBlockStatement : BoundStatement
{
public BoundScope Scope { get; internal init; }
public IReadOnlyList<BoundStatement> Statements { get; internal init; }

public override BoundNode Accept(BoundTreeVisitor visitor) => visitor.VisitBoundBlockStatement(this);
}

public partial class Binder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
namespace Todl.Compiler.CodeAnalysis.Binding.BoundTree;

[BoundNode]
public sealed class BoundBreakStatement : BoundStatement
internal sealed class BoundBreakStatement : BoundStatement
{
public BoundLoopContext BoundLoopContext { get; internal init; }

public override BoundNode Accept(BoundTreeVisitor visitor) => visitor.VisitBoundBreakStatement(this);
}

public partial class Binder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@
namespace Todl.Compiler.CodeAnalysis.Binding.BoundTree;

[BoundNode]
public sealed class BoundClrFunctionCallExpression : BoundExpression
internal sealed class BoundClrFunctionCallExpression : BoundExpression
{
public BoundExpression BoundBaseExpression { get; internal init; }
public MethodInfo MethodInfo { get; internal init; }
public IReadOnlyList<BoundExpression> BoundArguments { get; internal init; }
public override TypeSymbol ResultType => BoundBaseExpression.SyntaxNode.SyntaxTree.ClrTypeCache.Resolve(MethodInfo.ReturnType);
public bool IsStatic => MethodInfo.IsStatic;

public override BoundNode Accept(BoundTreeVisitor visitor) => visitor.VisitBoundClrFunctionCallExpression(this);
}

public partial class Binder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
namespace Todl.Compiler.CodeAnalysis.Binding.BoundTree;

[BoundNode]
public sealed class BoundConditionalStatement : BoundStatement
internal sealed class BoundConditionalStatement : BoundStatement
{
public BoundExpression Condition { get; internal init; }
public BoundStatement Consequence { get; internal init; }
Expand Down Expand Up @@ -35,6 +35,8 @@ public BoundConditionalStatement Validate()

return this;
}

public override BoundNode Accept(BoundTreeVisitor visitor) => visitor.VisitBoundConditionalStatement(this);
}

public partial class Binder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
namespace Todl.Compiler.CodeAnalysis.Binding.BoundTree;

[BoundNode]
public sealed class BoundConstant : BoundExpression
internal sealed class BoundConstant : BoundExpression
{
public ConstantValue Value { get; internal init; }

public override TypeSymbol ResultType => Value.ResultType;

public override bool Constant => true;

public override BoundNode Accept(BoundTreeVisitor visitor) => visitor.VisitBoundConstant(this);
}

public partial class Binder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
namespace Todl.Compiler.CodeAnalysis.Binding.BoundTree;

[BoundNode]
public sealed class BoundContinueStatement : BoundStatement
internal sealed class BoundContinueStatement : BoundStatement
{
public BoundLoopContext BoundLoopContext { get; internal init; }

public override BoundNode Accept(BoundTreeVisitor visitor) => visitor.VisitBoundContinueStatement(this);
}

public partial class Binder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@

namespace Todl.Compiler.CodeAnalysis.Binding.BoundTree;

public sealed class BoundEntryPointTypeDefinition : BoundTodlTypeDefinition
[BoundNode]
internal sealed class BoundEntryPointTypeDefinition : BoundTodlTypeDefinition
{
public const string EntryPointFunctionName = "Main";
public const string GeneratedTypeName = "_Todl_Generated_EntryPoint_";
Expand Down Expand Up @@ -53,11 +54,13 @@ private bool IsEntryPointCandidate(BoundFunctionMember f)

return true;
}

public override BoundNode Accept(BoundTreeVisitor visitor) => visitor.VisitBoundEntryPointTypeDefinition(this);
}

public partial class Binder
{
public BoundEntryPointTypeDefinition BindEntryPointTypeDefinition(IEnumerable<SyntaxTree> syntaxTrees)
internal BoundEntryPointTypeDefinition BindEntryPointTypeDefinition(IEnumerable<SyntaxTree> syntaxTrees)
{
var typeBinder = CreateTypeBinder();
var diagnosticBuilder = new DiagnosticBag.Builder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Todl.Compiler.CodeAnalysis.Binding.BoundTree;

public abstract class BoundExpression : BoundNode
internal abstract class BoundExpression : BoundNode
{
public virtual TypeSymbol ResultType { get; }
public virtual bool LValue => false;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
using Todl.Compiler.CodeAnalysis.Syntax;

namespace Todl.Compiler.CodeAnalysis.Binding.BoundTree
namespace Todl.Compiler.CodeAnalysis.Binding.BoundTree;

[BoundNode]
internal sealed class BoundExpressionStatement : BoundStatement
{
[BoundNode]
public sealed class BoundExpressionStatement : BoundStatement
{
public BoundExpression Expression { get; internal init; }
}
public BoundExpression Expression { get; internal init; }

public override BoundNode Accept(BoundTreeVisitor visitor) => visitor.VisitBoundExpressionStatement(this);
}

public partial class Binder
{
private BoundExpressionStatement BindExpressionStatement(ExpressionStatement expressionStatement)
=> BoundNodeFactory.CreateBoundExpressionStatement(
syntaxNode: expressionStatement,
expression: BindExpression(expressionStatement.Expression));
}
public partial class Binder
{
private BoundExpressionStatement BindExpressionStatement(ExpressionStatement expressionStatement)
=> BoundNodeFactory.CreateBoundExpressionStatement(
syntaxNode: expressionStatement,
expression: BindExpression(expressionStatement.Expression));
}
Loading

0 comments on commit 884aeac

Please sign in to comment.