/// <summary> /// Get the parent node of a node /// </summary> /// <remarks> /// This is an expensive operation, as the whole tree will be searched through /// </remarks> public static ParseTreeNode Parent(this ParseTreeNode child, ParseTreeNode treeRoot) { var parent = treeRoot.AllNodes() .FirstOrDefault(node => node.ChildNodes.Any(c => c == child)); if (parent == null) { throw new ArgumentException("Child is not part of the tree", nameof(child)); } return(parent); }
public void SheetNamesWithSpacesCanBeExtractedCorrectly() { var strangeSheetNames = new[] { "\t", " ", " ", " A", " ''A", " A ", " ''A1'' " }; foreach (var sheetName in strangeSheetNames) { // Simple reference to another sheet var sourceText = $"'{sheetName}'!A1"; ParseTreeNode node = ExcelFormulaParser.Parse(sourceText); var actual = node.AllNodes(GrammarNames.Prefix).First().GetPrefixInfo().Sheet; Assert.AreEqual(sheetName, actual); } }
private static IEnumerable <ParseTreeNode> CellContainedInRanges(ParseTreeNode fqcellref, ParseTreeNode formula, Context CtxF) { var cell = new Location(fqcellref.ChildNodes[1].Print()); // Select all references and qualify them var references = formula.GetReferenceNodes().Select(CtxF.Qualify).ToList(); // Check the different types of ranges var ranges = formula.AllNodes().Where(reference => reference.MatchFunction(":")); var rangesc = ranges.Where(range => { var args = range.GetFunctionArguments().Select(ExcelFormulaParser.Print).ToList(); var start = new Location(args[0]); var end = new Location(args[1]); return(cell.Row >= start.Row && cell.Row <= end.Row && cell.Column >= start.Column && cell.Column <= end.Column); }); var vranges = references.Where(reference => reference.ChildNodes[0].Is(GrammarNames.Prefix) && reference.ChildNodes[1].Is(GrammarNames.VerticalRange) ); var vrangesc = vranges.Where(reference => { var vrange = reference.ChildNodes[1]; var pieces = vrange.Print().Replace("$", "").Split(':'); return(cell.Column >= AuxConverter.ColToInt(pieces[0]) && cell.Column <= AuxConverter.ColToInt(pieces[1])); }); var hranges = references.Where(reference => reference.ChildNodes[0].Is(GrammarNames.Prefix) && reference.ChildNodes[1].Is(GrammarNames.HorizontalRange) ); var hrangesc = hranges.Where(reference => { var hrange = reference.ChildNodes[1]; var pieces = hrange.Print().Replace("$", "").Split(':'); return(cell.Row >= (int.Parse(pieces[0]) - 1) && cell.Row <= (int.Parse(pieces[1]) - 1)); }); var combined = new[] { rangesc, vrangesc, hrangesc }.SelectMany(x => x); return(combined); }
private static bool NodeCanBeGrouped(ParseTreeNode node) { // can be grouped if the node is a reference var relevant = node.SkipToRelevant(); return(relevant.Is(GrammarNames.Reference) // And it's not && !node.AllNodes().Any(childnode => // named ranges childnode.Is(GrammarNames.NamedRange) // vertical or horizontal ranges || childnode.Is(GrammarNames.HorizontalRange) || childnode.Is(GrammarNames.VerticalRange) // structured references || childnode.Is(GrammarNames.StructureReference) // Error || childnode.Is(GrammarNames.RefError) // Reference Functions || childnode.IsFunction() )); }
public override ParseTreeNode Refactor(ParseTreeNode applyto) { if (excel == null) { throw new InvalidOperationException("Must have reference to Excel worksheet to group references"); } var targetFunctions = applyto.AllNodes() .Where(IsTargetFunction) .ToList(); foreach (var function in targetFunctions) { var arguments = function.GetFunctionArguments().Select(node => node.SkipToRelevant()).ToList(); var unions = arguments .Select(arg => arg.ChildNodes.Count > 0 ? arg.ChildNodes[0] : arg) .Where(ExcelFormulaParser.IsUnion); // Group Union arguments foreach (var fcall in unions) { var args = fcall.GetFunctionArguments().ToList(); var union = fcall.ChildNodes[0]; var newargs = GroupReferenceList(args); union.ChildNodes.Clear(); union.ChildNodes.AddRange(newargs); } // If this is a varags function group all arguments if (varargsFunctions.Contains(function.GetFunction())) { var newargs = GroupReferenceList(arguments).ToList(); function.ChildNodes[1].ChildNodes.Clear(); function.ChildNodes[1].ChildNodes.AddRange(newargs); } } return(applyto); }
public override bool CanRefactor(ParseTreeNode applyto) { return(applyto.AllNodes().Any(IsTargetFunction)); }
/// <summary> /// All non-terminal nodes of a certain type in depth-first pre-order /// </summary> public static IEnumerable <ParseTreeNode> AllNodes(this ParseTreeNode root, string type) { return(AllNodes(root.AllNodes(), type)); }
/// <summary> /// Whether this tree contains any nodes of a type /// </summary> public static bool Contains(this ParseTreeNode root, string type) { return(root.AllNodes(type).Any()); }
/// <summary> /// Get the parent node of a node /// </summary> /// <remarks> /// This is an expensive operation, as the whole tree will be searched through /// </remarks> public static ParseTreeNode Parent(this ParseTreeNode child, ParseTreeNode treeRoot) { var parent = treeRoot.AllNodes() .FirstOrDefault(node => node.ChildNodes.Any(c => c == child)); if(parent == null) throw new ArgumentException("Child is not part of the tree", nameof(child)); return parent; }