/// <summary>
        /// Used by Parser.java to process VMs withing the parsing process
        ///
        /// processAndRegister() doesn't actually render the macro to the output
        /// Processes the macro body into the internal representation used by the
        /// VelocimacroProxy objects, and if not currently used, adds it
        /// to the macro Factory
        /// </summary>
        public static void processAndRegister(RuntimeServices rs, Node node, String sourceTemplate)
        {
            /*
             *  There must be at least one arg to  #macro,
             *  the name of the VM.  Note that 0 following
             *  args is ok for naming blocks of HTML
             */
            int numArgs = node.jjtGetNumChildren();

            /*
             *  this number is the # of args + 1.  The + 1
             *  is for the block tree
             */
            if (numArgs < 2)
            {
                /*
                 *  error - they didn't name the macro or
                 *  define a block
                 */
                rs.error("#macro error : Velocimacro must have name as 1st " + "argument to #macro()");

                return;
            }

            /*
             *  get the arguments to the use of the VM
             */
            String[] argArray = getArgArray(node);

            /*
             *   now, try and eat the code block. Pass the root.
             */
            IList macroArray = getASTAsStringArray(node.jjtGetChild(numArgs - 1));

            /*
             *  make a big string out of our macro
             */
            StringBuilder temp = new StringBuilder();

            for (int i = 0; i < macroArray.Count; i++)
            {
                temp.Append(macroArray[i]);
            }

            String macroBody = temp.ToString();

            /*
             * now, try to add it.  The Factory controls permissions,
             * so just give it a whack...
             */
            bool bRet = rs.addVelocimacro(argArray[0], macroBody, argArray, sourceTemplate);

            return;
        }
        /// <summary>  creates an array containing the literal
        /// strings in the macro arguement
        /// </summary>
        private static String[] getArgArray(Node node)
        {
            /*
             *  remember : this includes the block tree
             */

            int numArgs = node.jjtGetNumChildren();

            numArgs--;             // avoid the block tree...

            String[] argArray = new String[numArgs];

            int i = 0;

            /*
             *  eat the args
             */

            while (i < numArgs)
            {
                argArray[i] = node.jjtGetChild(i).FirstToken.image;

                /*
                 *  trim off the leading $ for the args after the macro name.
                 *  saves everyone else from having to do it
                 */

                if (i > 0)
                {
                    if (argArray[i].StartsWith("$"))
                    {
                        argArray[i] = argArray[i].Substring(1, (argArray[i].Length) - (1));
                    }
                }

                i++;
            }

            if (debugMode)
            {
                Console.Out.WriteLine("Macro.getArgArray() : #args = " + numArgs);
                Console.Out.Write(argArray[0] + "(");

                for (i = 1; i < numArgs; i++)
                {
                    Console.Out.Write(" " + argArray[i]);
                }

                Console.Out.WriteLine(" )");
            }

            return(argArray);
        }