Exemplo n.º 1
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));
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Go to the first "relevant" child node, i.e. skips wrapper nodes
        /// </summary>
        /// <param name="input">The input parse tree node</param>
        /// <param name="skipReferencesWithoutPrefix">If true, skip all reference nodes without a prefix instead of only parentheses</param>
        /// <remarks>
        /// Skips:
        /// * FormulaWithEq and ArrayFormula nodes
        /// * Formula nodes
        /// * Parentheses
        /// * Reference nodes which are just wrappers
        /// </remarks>
        public static ParseTreeNode SkipToRelevant(this ParseTreeNode input, bool skipReferencesWithoutPrefix = false)
        {
            while (true)
            {
                switch (input.Type())
                {
                case GrammarNames.FormulaWithEq:
                case GrammarNames.ArrayFormula:
                    input = input.ChildNodes[1];
                    break;

                case GrammarNames.Argument:
                case GrammarNames.Formula:
                    if (input.ChildNodes.Count == 1)
                    {
                        input = input.ChildNodes[0];
                    }
                    else
                    {
                        return(input);
                    }
                    break;

                case GrammarNames.Reference:
                    // Skip references which are parentheses
                    // Skip references without a prefix (=> they only have one child node) if the option is set
                    if ((skipReferencesWithoutPrefix && input.ChildNodes.Count == 1) || input.IsParentheses())
                    {
                        input = input.ChildNodes[0];
                    }
                    else
                    {
                        return(input);
                    }
                    break;

                default:
                    return(input);
                }
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Print transformation rule grammar
        /// </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;

            string ret;

            // Switch on nonterminals
            switch (input.Term.Name)
            {
            case TransformationRuleGrammar.Names.VarExpression:
            case TransformationRuleGrammar.Names.DynamicCell:
            case TransformationRuleGrammar.Names.DynamicConstant:
            case TransformationRuleGrammar.Names.DynamicRange:
                return(string.Join("", input.ChildNodes));

            case GrammarNames.Formula:
                // Check if these are brackets, otherwise print first child
                return(input.IsParentheses() ? $"({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.Join(",", childsL)})");
                }

                if (input.IsUnaryOperation())
                {
                    return(string.Join("", childsL));
                }

                throw new ArgumentException("Unknown function type.");

            case GrammarNames.Reference:
                if (input.IsParentheses())
                {
                    return($"({childs.First()})");
                }

                return(string.Join("", childs));

            case GrammarNames.Prefix:
                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.StructureReference:
                ret = "";
                var hastable     = input.ChildNodes.Count == 2;
                var contentsNode = hastable ? 1 : 0;
                childsL = childs.ToList();
                if (hastable)
                {
                    ret += childsL[0];
                }

                if (input.ChildNodes[contentsNode].Is(GrammarNames.StructureReferenceColumnOrKeyword))
                {
                    ret += childsL[contentsNode];
                }
                else
                {
                    ret += $"[{childsL[contentsNode]}]";
                }

                return(ret);

            // Terms for which to print all child nodes concatenated
            case GrammarNames.ArrayConstant:
            case GrammarNames.DynamicDataExchange:
            case GrammarNames.FormulaWithEq:
            case GrammarNames.File:
            case GrammarNames.StructureReferenceExpression:
                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($"{{{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($"Could not print node of type '{input.Term.Name}'.\nThis probably means the excel grammar was modified without the print function being modified");
            }
        }