/// <summary> /// Get the function or operator name of this function call /// </summary> public static string GetFunction(this ParseTreeNode input) { if (input.IsIntersection()) { return(GrammarNames.TokenIntersect); } if (input.IsUnion()) { return(GrammarNames.TokenUnionOperator); } if (input.IsBinaryOperation() || input.IsUnaryPostfixOperation()) { return(input.ChildNodes[1].Print()); } if (input.IsUnaryPrefixOperation()) { return(input.ChildNodes[0].Print()); } if (input.IsNamedFunction()) { return(RemoveFinalSymbol(input.ChildNodes[0].Print()).ToUpper()); } if (input.IsExternalUDFunction()) { return($"{input.ChildNodes[0].Print()}{GetFunction(input.ChildNodes[1])}"); } throw new ArgumentException("Not a function call", nameof(input)); }
/// <summary> /// Pretty-print a parse tree to a string /// </summary> public static string Print(this ParseTreeNode input) { // For terminals, just print the token text if (input.Term is Terminal) { return(input.Token.Text); } // (Lazy) enumerable for printed children var children = input.ChildNodes.Select(Print); // Concrete list when needed List <string> childrenList; // Switch on non-terminals switch (input.Term.Name) { case GrammarNames.Formula: // Check if these are brackets, otherwise print first child return(IsParentheses(input) ? $"({children.First()})" : children.First()); case GrammarNames.FunctionCall: case GrammarNames.ReferenceFunctionCall: case GrammarNames.UDFunctionCall: childrenList = children.ToList(); if (input.IsNamedFunction()) { return(string.Join("", childrenList) + ")"); } if (input.IsBinaryOperation()) { // format string for "normal" binary operation string format = "{0} {1} {2}"; if (input.IsIntersection()) { format = "{0} {2}"; } else if (input.IsBinaryReferenceOperation()) { format = "{0}{1}{2}"; } return(string.Format(format, childrenList[0], childrenList[1], childrenList[2])); } if (input.IsUnion()) { return($"({string.Join(",", childrenList)})"); } if (input.IsUnaryOperation()) { return(string.Join("", childrenList)); } throw new ArgumentException("Unknown function type."); case GrammarNames.Reference: return(IsParentheses(input) ? $"({children.First()})" : string.Concat(children)); case GrammarNames.Prefix: var ret = string.Join("", children); // The exclamation mark token is not included in the parse tree, so we have to add that if it's a single file if (input.ChildNodes.Count == 1 && input.ChildNodes[0].Is(GrammarNames.File)) { ret += "!"; } return(ret); case GrammarNames.ArrayFormula: return("{=" + children.ElementAt(1) + "}"); case GrammarNames.StructuredReference: var sb = new StringBuilder(); var hashtable = input.ChildNodes.Count >= 1 && input.ChildNodes[0].Is(GrammarNames.StructuredReferenceTable); var contentsNode = hashtable ? 1 : 0; childrenList = children.ToList(); if (hashtable) { sb.Append(childrenList[0]); } if (hashtable && input.ChildNodes.Count == 1) { // Full table reference sb.Append("[]"); } else if (input.ChildNodes[contentsNode].Is(GrammarNames.StructuredReferenceElement)) { sb.Append(childrenList[contentsNode]); } else { sb.Append($"[{childrenList[contentsNode]}]"); } return(sb.ToString()); // Terms for which to print all child nodes concatenated case GrammarNames.ArrayConstant: case GrammarNames.DynamicDataExchange: case GrammarNames.FormulaWithEq: case GrammarNames.File: case GrammarNames.StructuredReferenceExpression: return(string.Join("", children)); // Terms for which we print the children comma-separated case GrammarNames.Arguments: case GrammarNames.ArrayRows: case GrammarNames.Union: return(string.Join(",", children)); case GrammarNames.ArrayColumns: return(string.Join(";", children)); case GrammarNames.ConstantArray: return($"{{{children.First()}}}"); default: // If it is not defined above and the number of children is exactly one, we want to just print the first child if (input.ChildNodes.Count == 1) { return(children.First()); } throw new ArgumentException($"Could not print node of type '{input.Term.Name}'." + Environment.NewLine + "This probably means the Excel grammar was modified without the print function being modified"); } }
/// <summary> /// Pretty-print a parse tree to a string /// </summary> public static string Print(this ParseTreeNode input) { // For terminals, just print the token text if (input.Term is Terminal) { return(input.Token.Text); } // (Lazy) enumerable for printed childs var childs = input.ChildNodes.Select(Print); // Concrete list when needed List <String> childsL; // Switch on nonterminals switch (input.Term.Name) { case GrammarNames.Formula: // Check if these are brackets, otherwise print first child return(IsParentheses(input) ? String.Format("({0})", childs.First()) : childs.First()); case GrammarNames.FunctionCall: case GrammarNames.ReferenceFunctionCall: case GrammarNames.UDFunctionCall: childsL = childs.ToList(); if (input.IsNamedFunction()) { return(String.Join("", childsL) + ")"); } if (input.IsBinaryOperation()) { // format string for "normal" binary operation string format = "{0} {1} {2}"; if (input.IsIntersection()) { format = "{0} {2}"; } else if (input.IsBinaryReferenceOperation()) { format = "{0}{1}{2}"; } return(String.Format(format, childsL[0], childsL[1], childsL[2])); } if (input.IsUnion()) { return(String.Format("({0})", String.Join(",", childsL))); } if (input.IsUnaryOperation()) { return(String.Join("", childsL)); } throw new ArgumentException("Unknown function type."); case GrammarNames.Reference: /*if (IsParentheses(input) || IsUnion(input)) * { * return String.Format("({0})", childs.First()); * } * * childsL = childs.ToList(); * if (IsIntersection(input)) * { * return String.Format("{0} {1}", childsL[0], childsL[2]); * } * * if (IsBinaryOperation(input)) * { * return String.Format("{0}{1}{2}", childsL[0], childsL[1], childsL[2]); * }*/ if (IsParentheses(input)) { return(String.Format("({0})", childs.First())); } return(String.Join("", childs)); case GrammarNames.File: return(String.Format("[{0}]", childs.First())); case GrammarNames.Prefix: var ret = String.Join("", childs); // The exclamation mark token is not included in the parse tree, so we have to add that if it's a single file if (input.ChildNodes.Count == 1 && input.ChildNodes[0].Is(GrammarNames.File)) { ret += "!"; } return(ret); case GrammarNames.ArrayFormula: return("{=" + childs.ElementAt(1) + "}"); case GrammarNames.DynamicDataExchange: childsL = childs.ToList(); return(String.Format("{0}!{1}", childsL[0], childsL[1])); // Terms for which to print all child nodes concatenated case GrammarNames.ArrayConstant: case GrammarNames.FormulaWithEq: return(String.Join("", childs)); // Terms for which we print the childs comma-separated case GrammarNames.Arguments: case GrammarNames.ArrayRows: case GrammarNames.Union: return(String.Join(",", childs)); case GrammarNames.ArrayColumns: return(String.Join(";", childs)); case GrammarNames.ConstantArray: return(String.Format("{{{0}}}", childs.First())); default: // If it is not defined above and the number of childs is exactly one, we want to just print the first child if (input.ChildNodes.Count == 1) { return(childs.First()); } throw new ArgumentException(String.Format("Could not print node of type '{0}'.\nThis probably means the excel grammar was modified without the print function being modified", input.Term.Name)); } }