/// <summary> /// Gets the ParserReferences from the input parse tree node and its children /// </summary> /// <remarks> /// 5 cases: /// 1. ReferenceItem node: convert to ParserReference /// 2. Reference node (Prefix ReferenceItem): convert to ParserReference, recursive call on the nodes returned from GetReferenceNodes(node) /// (to include the references in the arguments of external UDFs) /// 3. Range node (Cell:Cell): recursive call to retrieve the 2 limits, create ParserReference of type CellRange /// 4. Range node with complex limits: recursive call to retrieve limits as 2 ParserReferences /// 5. Other cases (RefFunctionCall, Union, Arguments):recursive call on the nodes returned from GetReferenceNodes(node) /// </remarks> public static IEnumerable <ParserReference> GetParserReferences(this ParseTreeNode node) { if (node.Type() == GrammarNames.Reference && node.ChildNodes.Count == 1) { node = node.ChildNodes[0]; } var list = new List <ParserReference>(); switch (node.Type()) { case GrammarNames.Cell: case GrammarNames.NamedRange: case GrammarNames.HorizontalRange: case GrammarNames.VerticalRange: case GrammarNames.StructuredReference: list.Add(new ParserReference(node)); break; case GrammarNames.Reference: list.Add(new ParserReference(node)); list.AddRange(node.ChildNodes[1].GetReferenceNodes().SelectMany(x => x.GetParserReferences())); break; default: if (node.IsRange()) { var rangeStart = GetParserReferences(node.ChildNodes[0].SkipToRelevant()).ToArray(); var rangeEnd = GetParserReferences(node.ChildNodes[2].SkipToRelevant()).ToArray(); if (IsCellReference(rangeStart) && IsCellReference(rangeEnd)) { ParserReference range = rangeStart.First(); range.MaxLocation = rangeEnd.First().MinLocation; range.ReferenceType = ReferenceType.CellRange; range.LocationString = node.Print(); list.Add(range); } else { list.AddRange(rangeStart); list.AddRange(rangeEnd); } } else { list.AddRange(node.GetReferenceNodes().SelectMany(x => x.GetParserReferences())); } break; } return(list); }
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); }