using System; using System.Collections.Immutable; using static Parser.Binding.BoundNodeFactory; namespace Parser.Binding { public abstract class BoundTreeRewriter { public virtual BoundStatement RewriteStatement(BoundStatement node) { return node.Kind switch { BoundNodeKind.AbstractMethodDeclaration => RewriteAbstractMethodDeclaration((BoundAbstractMethodDeclaration)node), BoundNodeKind.BlockStatement => RewriteBlockStatement((BoundBlockStatement)node), BoundNodeKind.ClassDeclaration => RewriteClassDeclaration((BoundClassDeclaration)node), BoundNodeKind.ConcreteMethodDeclaration => RewriteConcreteMethodDeclaration((BoundConcreteMethodDeclaration)node), BoundNodeKind.ConditionalGotoStatement => RewriteConditionalGotoStatement((BoundConditionalGotoStatement)node), BoundNodeKind.EmptyStatement => RewriteEmptyStatement((BoundEmptyStatement)node), BoundNodeKind.ExpressionStatement => RewriteExpressionStatement((BoundExpressionStatement)node), BoundNodeKind.ForStatement => RewriteForStatement((BoundForStatement)node), BoundNodeKind.FunctionDeclaration => RewriteFunctionDeclaration((BoundFunctionDeclaration)node), BoundNodeKind.GotoStatement => RewriteGotoStatement((BoundGotoStatement)node), BoundNodeKind.IfStatement => RewriteIfStatement((BoundIfStatement)node), BoundNodeKind.LabelStatement => RewriteLabelStatement((BoundLabelStatement)node), BoundNodeKind.SwitchStatement => RewriteSwitchStatement((BoundSwitchStatement)node), BoundNodeKind.TryCatchStatement => RewriteTryCatchStatement((BoundTryCatchStatement)node), BoundNodeKind.TypedVariableDeclaration => RewriteTypedVariableDeclaration((BoundTypedVariableDeclaration)node), BoundNodeKind.WhileStatement => RewriteWhileStatement((BoundWhileStatement)node), _ => throw new Exception($"Invalid statement kind {node.Kind}."), }; } public virtual BoundStatement RewriteTypedVariableDeclaration(BoundTypedVariableDeclaration node) { return node; } public virtual BoundStatement RewriteGotoStatement(BoundGotoStatement node) { return node; } public virtual BoundStatement RewriteConditionalGotoStatement(BoundConditionalGotoStatement node) { var condition = RewriteExpression(node.Condition); if (condition == node.Condition) { return node; } return ConditionalGoto(node.Syntax, condition, node.Label, node.GotoIfTrue); } public virtual BoundStatement RewriteWhileStatement(BoundWhileStatement node) { throw new NotImplementedException(); } public virtual BoundStatement RewriteTryCatchStatement(BoundTryCatchStatement node) { throw new NotImplementedException(); } public virtual BoundStatement RewriteSwitchStatement(BoundSwitchStatement node) { throw new NotImplementedException(); } public virtual BoundStatement RewriteLabelStatement(BoundLabelStatement node) { return node; } public virtual BoundStatement RewriteIfStatement(BoundIfStatement node) { var condition = RewriteExpression(node.Condition); var body = RewriteStatement(node.Body); ImmutableArray.Builder? builder = null; for (var i = 0; i < node.ElseifClauses.Length; i++) { var oldClause = node.ElseifClauses[i]; var newClause = RewriteElseifClause(oldClause); if (oldClause != newClause && builder is null) { builder = ImmutableArray.CreateBuilder(node.ElseifClauses.Length); for (var j = 0; j < i; j++) { builder.Add(node.ElseifClauses[j]); } } if (builder is not null) { builder.Add(newClause); } } var elseIfClauses = builder is null ? node.ElseifClauses : builder.MoveToImmutable(); var elseClause = node.ElseClause is null ? null : RewriteStatement(node.ElseClause); if (condition == node.Condition && body == node.Body && elseIfClauses == node.ElseifClauses && elseClause == node.ElseClause ) { return node; } return IfStatement(node.Syntax, condition, body, elseIfClauses, elseClause); } public virtual BoundElseifClause RewriteElseifClause(BoundElseifClause node) { var condition = RewriteExpression(node.Condition); var body = RewriteStatement(node.Body); if (condition == node.Condition && body == node.Body) { return node; } return ElseifClause(node.Syntax, condition, body); } public virtual BoundStatement RewriteFunctionDeclaration(BoundFunctionDeclaration node) { throw new NotImplementedException(); } public virtual BoundStatement RewriteForStatement(BoundForStatement node) { return node; } public virtual BoundStatement RewriteExpressionStatement(BoundExpressionStatement node) { var expression = RewriteExpression(node.Expression); if (expression == node.Expression) { return node; } return ExpressionStatement(node.Syntax, expression, node.DiscardResult); } public virtual BoundStatement RewriteEmptyStatement(BoundEmptyStatement node) { throw new NotImplementedException(); } public virtual BoundStatement RewriteConcreteMethodDeclaration(BoundConcreteMethodDeclaration node) { throw new NotImplementedException(); } public virtual BoundStatement RewriteClassDeclaration(BoundClassDeclaration node) { throw new NotImplementedException(); } public virtual BoundStatement RewriteBlockStatement(BoundBlockStatement node) { ImmutableArray.Builder? builder = null; for (var i = 0; i < node.Statements.Length; i++) { var oldStatement = node.Statements[i]; var newStatement = RewriteStatement(oldStatement); if (oldStatement != newStatement && builder is null) { builder = ImmutableArray.CreateBuilder(node.Statements.Length); for (var j = 0; j < i; j++) { builder.Add(node.Statements[j]); } } if (builder is not null) { builder.Add(newStatement); } } if (builder is null) { return node; } return Block(node.Syntax, builder.MoveToImmutable()); } public virtual BoundStatement RewriteAbstractMethodDeclaration(BoundAbstractMethodDeclaration node) { throw new NotImplementedException(); } public virtual BoundExpression RewriteExpression(BoundExpression node) { return node.Kind switch { BoundNodeKind.ArrayLiteralExpression => RewriteArrayLiteralExpression((BoundArrayLiteralExpression)node), BoundNodeKind.AssignmentExpression => RewriteAssignmentExpression((BoundAssignmentExpression)node), BoundNodeKind.BinaryOperationExpression => RewriteBinaryOperationExpression((BoundBinaryOperationExpression)node), BoundNodeKind.CellArrayElementAccessExpression => RewriteCellArrayElementAccessExpression((BoundCellArrayElementAccessExpression)node), BoundNodeKind.CellArrayLiteralExpression => RewriteCellArrayLiteralExpression((BoundCellArrayLiteralExpression)node), BoundNodeKind.ClassInvokationExpression => RewriteClassInvokationExpression((BoundClassInvokationExpression)node), BoundNodeKind.CommandExpression => RewriteCommandExpression((BoundCommandExpression)node), BoundNodeKind.CompoundNameExpression => RewriteCompoundNameExpression((BoundCompoundNameExpression)node), BoundNodeKind.ConversionExpression => RewriteConversionExpression((BoundConversionExpression)node), BoundNodeKind.DoubleQuotedStringLiteralExpression => RewriteDoubleQuotedStringLiteralExpression((BoundDoubleQuotedStringLiteralExpression)node), BoundNodeKind.EmptyExpression => RewriteEmptyExpression((BoundEmptyExpression)node), BoundNodeKind.FunctionCallExpression => RewriteFunctionCallExpression((BoundFunctionCallExpression)node), BoundNodeKind.IdentifierNameExpression => RewriteIdentifierNameExpression((BoundIdentifierNameExpression)node), BoundNodeKind.IndirectMemberAccessExpression => RewriteIndirectMemberAccessExpression((BoundIndirectMemberAccessExpression)node), BoundNodeKind.LambdaExpression => RewriteLambdaExpression((BoundLambdaExpression)node), BoundNodeKind.MemberAccessExpression => RewriteMemberAccessExpression((BoundMemberAccessExpression)node), BoundNodeKind.NamedFunctionHandleExpression => RewriteNamedFunctionHandleExpression((BoundNamedFunctionHandleExpression)node), BoundNodeKind.NumberDoubleLiteralExpression => RewriteNumberDoubleLiteralExpression((BoundNumberDoubleLiteralExpression)node), BoundNodeKind.NumberIntLiteralExpression => RewriteNumberIntLiteralExpression((BoundNumberIntLiteralExpression)node), BoundNodeKind.StringLiteralExpression => RewriteStringLiteralExpression((BoundStringLiteralExpression)node), BoundNodeKind.TypedVariableExpression => RewriteTypedVariableExpression((BoundTypedVariableExpression)node), BoundNodeKind.UnaryOperationExpression => RewriteUnaryOperationExpression((BoundUnaryOperationExpression)node), BoundNodeKind.UnquotedStringLiteralExpression => RewriteUnquotedStringLiteralExpression((BoundUnquotedStringLiteralExpression)node), _ => throw new Exception($"Invalid expression kind {node.Kind}."), }; } public virtual BoundExpression RewriteConversionExpression(BoundConversionExpression node) { var operand = RewriteExpression(node.Expression); return Conversion(node.Syntax, node.TargetType, operand); } public virtual BoundExpression RewriteTypedVariableExpression(BoundTypedVariableExpression node) { return node; } public virtual BoundExpression RewriteUnquotedStringLiteralExpression(BoundUnquotedStringLiteralExpression node) { throw new NotImplementedException(); } public virtual BoundExpression RewriteUnaryOperationExpression(BoundUnaryOperationExpression node) { var operand = RewriteExpression(node.Operand); return new BoundUnaryOperationExpression(node.Syntax, node.Op, operand); } public virtual BoundExpression RewriteStringLiteralExpression(BoundStringLiteralExpression node) { return node; } public virtual BoundExpression RewriteNumberDoubleLiteralExpression(BoundNumberDoubleLiteralExpression node) { return node; } public virtual BoundExpression RewriteNumberIntLiteralExpression(BoundNumberIntLiteralExpression node) { return node; } public virtual BoundExpression RewriteNamedFunctionHandleExpression(BoundNamedFunctionHandleExpression node) { throw new NotImplementedException(); } public virtual BoundExpression RewriteMemberAccessExpression(BoundMemberAccessExpression node) { throw new NotImplementedException(); } public virtual BoundExpression RewriteLambdaExpression(BoundLambdaExpression node) { throw new NotImplementedException(); } public virtual BoundExpression RewriteIndirectMemberAccessExpression(BoundIndirectMemberAccessExpression node) { throw new NotImplementedException(); } public virtual BoundExpression RewriteIdentifierNameExpression(BoundIdentifierNameExpression node) { return node; } public virtual BoundExpression RewriteFunctionCallExpression(BoundFunctionCallExpression node) { ImmutableArray.Builder? builder = null; for (var i = 0; i < node.Arguments.Length; i++) { var oldArgument = node.Arguments[i]; var newArgument = RewriteExpression(oldArgument); if (oldArgument != newArgument && builder is null) { builder = ImmutableArray.CreateBuilder(node.Arguments.Length); for (var j = 0; j < i; j++) { builder.Add(node.Arguments[j]); } } if (builder is not null) { builder.Add(newArgument); } } if (builder is null) { return node; } return FunctionCall(node.Syntax, node.Name, builder.MoveToImmutable()); } public virtual BoundExpression RewriteEmptyExpression(BoundEmptyExpression node) { throw new NotImplementedException(); } public virtual BoundExpression RewriteDoubleQuotedStringLiteralExpression(BoundDoubleQuotedStringLiteralExpression node) { throw new NotImplementedException(); } public virtual BoundExpression RewriteCommandExpression(BoundCommandExpression node) { throw new NotImplementedException(); } public virtual BoundExpression RewriteCompoundNameExpression(BoundCompoundNameExpression node) { throw new NotImplementedException(); } public virtual BoundExpression RewriteClassInvokationExpression(BoundClassInvokationExpression node) { throw new NotImplementedException(); } public virtual BoundExpression RewriteCellArrayLiteralExpression(BoundCellArrayLiteralExpression node) { throw new NotImplementedException(); } public virtual BoundExpression RewriteCellArrayElementAccessExpression(BoundCellArrayElementAccessExpression node) { throw new NotImplementedException(); } public virtual BoundExpression RewriteBinaryOperationExpression(BoundBinaryOperationExpression node) { var left = RewriteExpression(node.Left); var right = RewriteExpression(node.Right); if (left == node.Left && right == node.Right) { return node; } return new BoundBinaryOperationExpression(node.Syntax, left, node.Op, right); } public virtual BoundExpression RewriteAssignmentExpression(BoundAssignmentExpression node) { var left = RewriteExpression(node.Left); var right = RewriteExpression(node.Right); if (left == node.Left && right == node.Right) { return node; } return Assignment(node.Syntax, left, right); } public virtual BoundExpression RewriteArrayLiteralExpression(BoundArrayLiteralExpression node) { throw new NotImplementedException(); } } }