Esempio n. 1
0
        /// <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));
        }
Esempio n. 2
0
        /// <summary>
        /// Change a C# parse tree to a F# AST
        /// </summary>
        public static FSharpTransform.Formula CreateFSharpTree(this ParseTreeNode input)
        {
            if (input.IsParentheses())
            {
                return(FSharpTransform.Formula.NewFunction("", ListModule.OfSeq(new [] { CreateFSharpTree(input.ChildNodes[0]) })));
            }

            input = input.SkipToRelevant();

            switch (input.Type())
            {
            case GrammarNames.FunctionCall:
            case GrammarNames.ReferenceFunctionCall:
            case GrammarNames.UDFunctionCall:
                var fname = input.GetFunction() + (input.IsNamedFunction()?"(":"");
                var args  = ListModule.OfSeq(input.GetFunctionArguments().Select(CreateFSharpTree));
                // Check for range
                if (fname == ":")
                {
                    return(makeFSharpRange(input));
                }
                return(FSharpTransform.makeFormula(fname, args));

            case GrammarNames.Reference:
                // ignore prefix
                return(CreateFSharpTree(input.ChildNodes.Count == 1 ? input.ChildNodes[0] : input.ChildNodes[1]));

            case GrammarNames.Cell:
                var L = new Location(input.Print());
                return(FSharpTransform.makeSuperCell(FSharpTransform.makeCell(L.Column, L.Row)));

            case GrammarNames.NamedRange:
                return(FSharpTransform.makeNamedRange(input.Print()));

            case TransformationRuleGrammar.Names.DynamicCell:
                //get variables from dynamic cell
                return(FSharpTransform.makeSuperCell(GetDynamicCell(input)));

            case TransformationRuleGrammar.Names.DynamicRange:
                var letter = input          // DynamicRange
                             .ChildNodes[0] // LowLetter
                             .Token.ValueString[0];
                return(FSharpTransform.makeDRange(letter));

            case GrammarNames.Constant:
            case GrammarNames.Number:
            case GrammarNames.Text:
            case GrammarNames.Bool:
            case GrammarNames.Error:
            case GrammarNames.RefError:
                return(FSharpTransform.makeConstant(input.Print()));

            case TransformationRuleGrammar.Names.DynamicConstant:
                return(FSharpTransform.makeDArgument(input.ChildNodes[0].Token.ValueString[1]));

            default:
                throw new ArgumentException($"Can't convert node type {input.Type()}", nameof(input));
            }
        }
Esempio n. 3
0
 private static bool IsTargetFunction(ParseTreeNode node)
 {
     return
         // Not interested in not-functions
         (node.IsNamedFunction()
          // Or functions without arguments
          && node.ChildNodes[1].ChildNodes.Any() &&
          (varargsFunctions.Contains(node.GetFunction())
           // Functions have an arrayasargument parameter
           || node.GetFunctionArguments().Any(n => n.SkipToRelevant().IsUnion())
          )
         );
 }
Esempio n. 4
0
 /// <summary>
 /// Get all the arguments of a function or operation
 /// </summary>
 public static IEnumerable <ParseTreeNode> GetFunctionArguments(this ParseTreeNode input)
 {
     if (input.IsNamedFunction())
     {
         return(input
                .ChildNodes[1] // "Arguments" non-terminal
                .ChildNodes    // "Argument" non-terminals
                .Select(node => node.ChildNodes[0])
                );
     }
     if (input.IsBinaryOperation())
     {
         return(new[] { input.ChildNodes[0], input.ChildNodes[2] });
     }
     if (input.IsUnaryPrefixOperation())
     {
         return(new[] { input.ChildNodes[1] });
     }
     if (input.IsUnaryPostfixOperation())
     {
         return(new[] { input.ChildNodes[0] });
     }
     if (input.IsUnion())
     {
         return(input.ChildNodes[0].ChildNodes);
     }
     if (input.IsExternalUDFunction())
     {
         return(input          // Reference
                .ChildNodes[1] // UDFunctionCall
                .ChildNodes[1] // Arguments
                .ChildNodes    // Argument non-terminals
                .Select(node => node.ChildNodes[0])
                );
     }
     throw new ArgumentException("Not a function call", nameof(input));
 }
Esempio n. 5
0
        /// <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");
            }
        }
Esempio n. 6
0
        /// <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));
            }
        }