Example #1
0
        /// <summary>
        /// Converts the subtree belonging to a node to a string
        /// </summary>
        /// <param name="lastChild">Whether or not this node is the last child at each parent level of the tree</param>
        /// <param name="node">The node to print</param>
        /// <returns>A string representation of the subtree rooted at the given node</returns>
        private static string ToString(ImmutableList <bool> lastChild, IAbstractSyntaxTreeNode node)
        {
            switch (node)
            {
            // Program
            case ProgramNode programNode:
                return(NodeToString(lastChild, programNode, programNode.Command));

            // Commands
            case AssignCommandNode assignCommand:
                return(NodeToString(lastChild, assignCommand, assignCommand.Identifier, assignCommand.Expression));

            case CallCommandNode callCommand:
                return(NodeToString(lastChild, callCommand, callCommand.Identifier, callCommand.Parameter));

            case IfCommandNode ifCommand:
                return(NodeToString(lastChild, ifCommand, ifCommand.Expression, ifCommand.ThenCommand));

            case IfElseCommandNode ifElseCommand:
                return(NodeToString(lastChild, ifElseCommand, ifElseCommand.Expression, ifElseCommand.ThenCommand, ifElseCommand.ElseCommand));

            case LetCommandNode letCommand:
                return(NodeToString(lastChild, letCommand, letCommand.Declaration, letCommand.Command));

            case SequentialCommandNode sequentialCommand:
                return(NodeToString(lastChild, sequentialCommand, sequentialCommand.Commands.ToArray()));

            // case EmptyCommandNode blankCommand:
            // return NodeToString(lastChild, blankCommand);
            case ForCommandNode forCommand:
                return(NodeToString(lastChild, forCommand.Identifier, forCommand.BecomesExpression, forCommand.ToExpression, forCommand.Command));

            // case BeginCommandNode beginCommand:
            //   return NodeToString(lastChild, beginCommand, beginCommand.Command);

            case WhileCommandNode whileCommand:
                return(NodeToString(lastChild, whileCommand, whileCommand.Expression, whileCommand.Command));

            // Declarations
            case ConstDeclarationNode constDeclaration:
                return(NodeToString(lastChild, constDeclaration, constDeclaration.Identifier, constDeclaration.Expression));

            case SequentialDeclarationNode sequentialDeclaration:
                return(NodeToString(lastChild, sequentialDeclaration, sequentialDeclaration.Declarations.ToArray()));

            case VarDeclarationNode varDeclaration:
                return(NodeToString(lastChild, varDeclaration, varDeclaration.TypeDenoter, varDeclaration.Identifier));

            // Expressions
            case BinaryExpressionNode binaryExpression:
                return(NodeToString(lastChild, binaryExpression, binaryExpression.LeftExpression, binaryExpression.Op, binaryExpression.RightExpression));

            case CharacterExpressionNode characterExpression:
                return(NodeToString(lastChild, characterExpression, characterExpression.CharLit));

            case IdExpressionNode idExpression:
                return(NodeToString(lastChild, idExpression, idExpression.Identifier));

            case IntegerExpressionNode integerExpression:
                return(NodeToString(lastChild, integerExpression, integerExpression.IntLit));

            case UnaryExpressionNode unaryExpression:
                return(NodeToString(lastChild, unaryExpression, unaryExpression.Op, unaryExpression.Expression));

            //case BracketExpressionNode bracketExpression:
            //  return NodeToString()

            // Parameters
            case EmptyParameterNode blankParameter:
                return(NodeToString(lastChild, blankParameter));

            case ValueParameterNode expressionParameter:
                return(NodeToString(lastChild, expressionParameter, expressionParameter.Expression));

            case VarParameterNode varParameter:
                return(NodeToString(lastChild, varParameter, varParameter.Identifier));

            // Types
            case TypeDenoterNode typeDenoter:
                return(NodeToString(lastChild, typeDenoter, typeDenoter.Identifier));

            // Terminals
            case CharacterLiteralNode characterLiteral:
                return(TerminalNodeToString(lastChild, characterLiteral, characterLiteral.CharacterLiteralToken));

            case IdentifierNode identifier:
                return(TerminalNodeToString(lastChild, identifier, identifier.IdentifierToken));

            case IntegerLiteralNode integerLiteral:
                return(TerminalNodeToString(lastChild, integerLiteral, integerLiteral.IntegerLiteralToken));

            case OperatorNode operation:
                return(TerminalNodeToString(lastChild, operation, operation.OperatorToken));

            // Error
            case ErrorNode errorNode:
                return(NodeToString(lastChild, errorNode));



            // Anything without a case written for it ends up here
            default:
                if (node == null)
                {
                    // Null - not a lot we can do
                    Debugger.WriteDebuggingInfo("Tried to print a null tree node");
                    return(NodeToString(lastChild, node));
                }
                else
                {
                    // Use reflection to try to draw node
                    Debugger.WriteDebuggingInfo($"Tried to print an unknown tree node type {node.GetType().Name}");
                    IAbstractSyntaxTreeNode[] children = GetChildNodes(node).Concat(GetCollectionOfChildNodes(node)).ToArray();
                    Token token = GetToken(node);
                    return(GeneralNodeToString(lastChild, node, token, children.Length == 0 ? null : children));
                }
            }
        }