Beispiel #1
0
        /// <summary>Recursively applies macros in scope to <c>input</c>.</summary>
        /// <param name="maxExpansions">Maximum number of opportunities given
        /// to macros to transform a given subtree. The output of any macro is
        /// transformed again (as if by calling this method) with
        /// <c>maxExpansions = maxExpansions - 1</c> to encourage the
        /// expansion process to terminate eventually.</param>
        /// <returns>Returns a transformed tree or null if the macros did not
        /// change the syntax tree at any level, paired with a flag that is
        /// true if the remainder of the nodes in the current list of nodes
        /// should be dropped.</returns>
        LNode ApplyMacros(LNode input, int maxExpansions, bool isTargetNode)
        {
            if (maxExpansions <= 0)
            {
                return(null);
            }
            _s.StartNextNode(input, maxExpansions, isTargetNode);

            // Find macros...
            LNode target;

            if (input.HasSimpleHead())
            {
                GetApplicableMacros(_curScope.OpenNamespaces, input.Name, _s.FoundMacros);
            }
            else if ((target = input.Target).Calls(S.Dot, 2) && target.Args[1].IsId)
            {
                Symbol name = target.Args[1].Name, @namespace = NamespaceToSymbol(target.Args[0]);
                GetApplicableMacros(@namespace, name, _s.FoundMacros);
            }

            _ancestorStack.PushLast(input);
            try {
                if (_s.FoundMacros.Count != 0)
                {
                    return(ApplyMacrosFound(_s));
                }
                else
                {
                    return(ApplyMacrosToChildrenOf(input, maxExpansions));
                }
            } finally {
                _ancestorStack.PopLast(1);
            }
        }
Beispiel #2
0
        /// <summary>Recursively applies macros in scope to <c>input</c>.</summary>
        /// <param name="maxExpansions">Maximum number of opportunities given
        /// to macros to transform a given subtree. The output of any macro is
        /// transformed again (as if by calling this method) with
        /// <c>maxExpansions = maxExpansions - 1</c> to encourage the
        /// expansion process to terminate eventually.</param>
        /// <returns>Returns a transformed tree (or null if the macros did not
        /// change the syntax tree at any level).</returns>
        LNode ApplyMacros(LNode input, int maxExpansions, bool isTargetNode, out bool dropRemainingNodes)
        {
            LNode resultNode = null;

            dropRemainingNodes = false;
            for (LNode curNode = input; maxExpansions > 0; curNode = resultNode)
            {
                _s.StartNextNode(curNode, maxExpansions, isTargetNode);
                GetApplicableMacros(curNode, _s.FoundMacros);
                if (_s.FoundMacros.Count == 0 && !curNode.IsCall)
                {
                    return(resultNode);                    // most common case: a boring leaf node
                }
                bool braces = curNode.Calls(S.Braces);
                if (braces)
                {
                    _scopes.Add(null);
                }

                MacroResult result;
                _ancestorStack.PushLast(curNode);
                try {
                    if (_s.FoundMacros.Count == 0)
                    {
                        return(ApplyMacrosToChildrenOf(curNode, maxExpansions) ?? resultNode);
                    }

                    // USER MACROS RUN HERE!
                    var result_ = ApplyMacrosFound(_s);
                    if (result_ == null)
                    {
                        // Macro(s) had no effect (not in this iteration, anyway),
                        // so move on to processing children.
                        return(_s.Preprocessed ?? ApplyMacrosToChildrenOf(curNode, maxExpansions) ?? resultNode);
                    }
                    result = result_.Value;
                } finally {
                    _ancestorStack.PopLast(1);
                    if (braces)
                    {
                        PopScope();
                    }
                }

                // Deal with result produced by the macro (unless Macro.NoReprocessing etc.)
                NodesReplaced++;
                Debug.Assert(result.NewNode != null);
                if (result.DropRemainingNodes)
                {
                    dropRemainingNodes = true;
                    _s.DropRemainingNodes();
                }

                // I don't think this has any effect
                //if ((result.Macro.Mode & MacroMode.ProcessChildrenBefore) != 0)
                //	_s.MaxExpansions--; // children already expanded

                resultNode = result.NewNode;
                if ((result.Macro.Mode & MacroMode.ProcessChildrenAfter) != 0)
                {
                    return(ApplyMacrosToChildrenOf(resultNode, maxExpansions - 1) ?? resultNode);
                }
                else if ((result.Macro.Mode & (MacroMode.NoReprocessing | MacroMode.ProcessChildrenBefore)) != 0)
                {
                    return(resultNode);                    // we're done!
                }
                else
                {
                    if (resultNode == curNode)
                    {
                        // node is unchanged, so reprocessing would produce the
                        // same result. Don't do that, just process children.
                        return(ApplyMacrosToChildrenOf(resultNode, maxExpansions - 1));
                    }
                    else
                    {
                        // Avoid deepening the call stack like we used to do...
                        //   result2 = ApplyMacros(result.NewNode, s.MaxExpansions - 1, s.IsTarget);
                        //   if (result2 != null) result.DropRemainingNodesRequested |= _s.DropRemainingNodesRequested;
                        // instead, iterate, changing our own parameters.
                        maxExpansions--;
                        Debug.Assert(isTargetNode == _s.IsTarget);
                    }
                }
            }
            return(resultNode);
        }
        /// <summary>Recursively applies macros in scope to <c>input</c>.</summary>
        /// <param name="maxExpansions">Maximum number of opportunities given
        /// to macros to transform a given subtree. The output of any macro is
        /// transformed again (as if by calling this method) with
        /// <c>maxExpansions = maxExpansions - 1</c> to encourage the
        /// expansion process to terminate eventually.</param>
        /// <param name="nodeQueue">The act of processing child nodes (by calling
        /// ApplyMacrosToChildrenOf) invalidates most members of _s including
        /// _s.NodeQueue. But when ApplyMacrosToList calls this method it needs
        /// the node queue, so this method saves _s.NodeQueue in nodeQueue before
        /// doing something that will destroy _s.NodeQueue. It also sets
        /// _s.NodeQueue = nodeQueue when it starts.</param>
        /// <returns>Returns a transformed tree (or null if the macros did not
        /// change the syntax tree at any level).</returns>
        /// <remarks>EnqueueSplice is used if a #splice(...) is encountered.</remarks>
        LNode ApplyMacros(LNode input, int maxExpansions, bool isTargetNode, bool isSingleNode, ref DList <Pair <LNode, int> > nodeQueue)
        {
            _s.NodeQueue = nodeQueue;
            int   maxExpansionsBefore = maxExpansions;
            LNode resultNode          = null;

            for (LNode curNode = input; maxExpansions > 0; curNode = resultNode)
            {
                // If #splice, expand it
                if (!isSingleNode && curNode.Calls(S.Splice))
                {
                    if (curNode.ArgCount == 0)
                    {
                        return(curNode);                        // #splice()
                    }
                    curNode = resultNode = _s.EnqueueSplice(curNode.Args, maxExpansions, maxExpansionsBefore);
                    Debug.Assert(curNode != null);
                }

                _s.StartNextNode(curNode, maxExpansions, isTargetNode);
                GetApplicableMacros(curNode, _s.FoundMacros);
                if (_s.FoundMacros.Count == 0 && curNode.ArgCount == 0 &&
                    curNode.HasSimpleHead() && !curNode.HasAttrs)
                {
                    nodeQueue = _s.NodeQueue;
                    return(resultNode);                    // most common case: a boring leaf node
                }

                bool braces = curNode.Calls(S.Braces);
                if (braces)
                {
                    _scopes.Add(null);
                }

                MacroResult result;
                _ancestorStack.PushLast(curNode);
                try {
                    if (_s.FoundMacros.Count == 0)
                    {
                        nodeQueue = _s.NodeQueue;
                        return(ApplyMacrosToChildrenOf(curNode, maxExpansions) ?? resultNode);
                    }

                    // USER MACROS RUN HERE!
                    var result_ = ApplyMacrosFound(_s);
                    if (result_ == null)
                    {
                        // Macro(s) had no effect (not in this iteration, anyway),
                        // so move on to processing children.
                        nodeQueue = _s.NodeQueue;
                        return(_s.Preprocessed ?? ApplyMacrosToChildrenOf(curNode, maxExpansions) ?? resultNode);
                    }
                    result = result_.Value;
                } finally {
                    _ancestorStack.PopLast(1);
                    if (braces)
                    {
                        PopScope();
                    }
                }

                // Deal with result produced by the macro
                NodesReplaced++;
                Debug.Assert(result.NewNode != null);
                _s.DropRemainingNodesIfRequested();

                resultNode = result.NewNode;
                nodeQueue  = _s.NodeQueue;
                if ((result.Macro.Mode & MacroMode.ProcessChildrenAfter) != 0)
                {
                    return(ApplyMacrosToChildrenOf(resultNode, maxExpansions - 1) ?? resultNode);
                }
                else if ((result.Macro.Mode & (MacroMode.NoReprocessing | MacroMode.ProcessChildrenBefore)) != 0)
                {
                    return(resultNode);                    // we're done!
                }
                else if (resultNode == curNode)
                {
                    // node is unchanged, so reprocessing would produce the
                    // same result. Don't do that, just process children.
                    return(ApplyMacrosToChildrenOf(resultNode, maxExpansions - 1) ?? resultNode);
                }
                else
                {
                    // Avoid deepening the call stack like we used to do...
                    //   result2 = ApplyMacros(result.NewNode, s.MaxExpansions - 1, s.IsTarget);
                    //   if (result2 != null) result.DropRemainingNodesRequested |= _s.DropRemainingNodesRequested;
                    // instead, iterate, changing our own parameters.
                    maxExpansions--;
                    Debug.Assert(isTargetNode == _s.IsTarget);
                }
            }
            nodeQueue = _s.NodeQueue;
            return(resultNode);
        }