/// <summary> /// Carries out code generation for a node /// </summary> /// <param name="node">The node to generate code for</param> private TargetCode GenerateCodeFor(IAbstractSyntaxTreeNode node) { if (node is null) { // Shouldn't have null nodes - there is a problem with your parsing Debugger.Write("Tried to generate code for a null tree node"); return(null); } else if (node is ErrorNode) { // Shouldn't have error nodes - there is a problem with your parsing Debugger.Write("Tried to generate code for an error tree node"); return(null); } else { string functionName = "GenerateCodeFor" + node.GetType().Name.Remove(node.GetType().Name.Length - 4); MethodInfo function = this.GetType().GetMethod(functionName, NonPublic | Public | Instance | Static); if (function == null) { // There is not a correctly named function below Debugger.Write($"Couldn't find the function {functionName} when generating code"); return(null); } else { return((TargetCode)function.Invoke(this, new[] { node })); } } }
/// <summary> /// Gets the token associated with a node /// </summary> /// <param name="node">The node to get the token for</param> /// <returns>The token associated with this node</returns> private static Token GetToken(IAbstractSyntaxTreeNode node) { return(node.GetType().GetProperties() .Where(property => property.PropertyType.GetType() == typeof(Token)) .Select(property => (Token)property.GetValue(node)) .FirstOrDefault()); }
/// <summary> /// Carries out type checking on a node /// </summary> /// <param name="node">The node to perform type checking on</param> private void PerformTypeChecking(IAbstractSyntaxTreeNode node) { if (node is null) { // Shouldn't have null nodes - there is a problem with your parsing Debugger.Write("Tried to perform type checking on a null tree node"); } else if (node is ErrorNode) { // Shouldn't have error nodes - there is a problem with your parsing Debugger.Write("Tried to perform type checking on an error tree node"); } else { string functionName = "PerformTypeCheckingOn" + node.GetType().Name.Remove(node.GetType().Name.Length - 4); MethodInfo function = this.GetType().GetMethod(functionName, NonPublic | Public | Instance | Static); if (function == null) { // There is not a correctly named function below Debugger.Write($"Couldn't find the function {functionName} when type checking"); } else { function.Invoke(this, new[] { node }); } } }
/// <summary> /// Gets children of a node which are in a collection /// </summary> /// <param name="node">The node to get children for</param> /// <returns>The children of the node which are in an immutable array</returns> private static List <IAbstractSyntaxTreeNode> GetCollectionOfChildNodes(IAbstractSyntaxTreeNode node) { // Find if there is a property of type ImmutableArray<X>, where X is a kind of node IEnumerable childCollection = node.GetType() .GetProperties() .Where(property => property.PropertyType.IsGenericType) .Where(property => property.PropertyType.GetGenericTypeDefinition() == typeof(ImmutableArray <>)) .Where(property => property.PropertyType .GetGenericArguments() .SingleOrDefault() .GetInterfaces() .Contains(typeof(IAbstractSyntaxTreeNode))) .Select(property => property.GetValue(node)) .FirstOrDefault() as IEnumerable; List <IAbstractSyntaxTreeNode> children = new List <IAbstractSyntaxTreeNode>(); if (childCollection != null) { foreach (object child in childCollection) { children.Add((IAbstractSyntaxTreeNode)child); } } return(children); }
/// <summary> /// Carries out identification on a node /// </summary> /// <param name="node">The node to perform identification on</param> private void PerformIdentification(IAbstractSyntaxTreeNode node) { if (node is null) { IsItDirty(); Reporter.IdentifierErrorPositions.Add($"Error has occured here:, null tree node"); // Shouldn't have null nodes - there is a problem with your parsing Debugger.Write("Tried to perform identification on a null tree node"); } else if (node is ErrorNode) { IsItDirty(); Reporter.IdentifierErrorPositions.Add($"Error has occured here: {node.Position}, error tree node."); // Shouldn't have error nodes - there is a problem with your parsing Debugger.Write("Tried to perform identification on an error tree node"); } else { string functionName = "PerformIdentificationOn" + node.GetType().Name.Remove(node.GetType().Name.Length - 4); MethodInfo function = this.GetType().GetMethod(functionName, NonPublic | Public | Instance | Static); if (function == null) { IsItDirty(); Reporter.IdentifierErrorPositions.Add($"Error has occured here: {node.Position}, {node.GetType()} function name is null "); // There is not a correctly named function below Debugger.Write($"Couldn't find the function {functionName} when doing identification"); } else { function.Invoke(this, new[] { node }); } } }
/// <summary> /// Gets the children of a node /// </summary> /// <param name="node">The node to get children for</param> /// <returns>The children of the node</returns> private static List <IAbstractSyntaxTreeNode> GetChildNodes(IAbstractSyntaxTreeNode node) { return(node.GetType().GetProperties() .Where(property => property.PropertyType .GetInterfaces() .Contains(typeof(IAbstractSyntaxTreeNode))) .Select(property => (IAbstractSyntaxTreeNode)property.GetValue(node)) .ToList()); }
/// <summary> /// Gets the name of a node /// </summary> /// <param name="node">The node to get the name of</param> /// <returns>A name based on the node's type</returns> private static string GetNodeName(IAbstractSyntaxTreeNode node) { string name = node.GetType().Name; return(name.EndsWith("Node") ? name.Substring(0, name.Length - 4) : name); }
/// <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 BeginCommandNode beginCommand: return(NodeToString(lastChild, beginCommand, beginCommand.Command)); 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 BlankCommandNode blankCommand: return(NodeToString(lastChild, blankCommand)); case WhileCommandNode whileCommand: return(NodeToString(lastChild, whileCommand, whileCommand.Expression, whileCommand.Command)); case ForCommandNode forCommand: return(NodeToString(lastChild, forCommand, forCommand.Assign, forCommand.Expression, forCommand.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)); // Parameters case EmptyParameterNode blankParameter: return(NodeToString(lastChild, blankParameter)); case ExpressionParameterNode 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.Write("Tried to print a null tree node"); return(NodeToString(lastChild, node)); } else { // Use reflection to try to draw node Debugger.Write($"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)); } } }