OK, I finally got back to doing interesting things (as opposed to what I
get paid for).  I modified G. Magnusson's template tool to display
equivalent forms only once (except that $Fred and ${Fred} still generate
separate references -- there is an easy fix but there is still a related
bug that I need to look at when I get a chance so I'm leaving it for
now).  It also gives a summary for all files passed (or only gives a
summary if -s is specified).  I've attached the source at the bottom.  I
want to make this "architecturally more proper" -- right now its a bit
of hack.

Sample call:
java TemplateTool templates/Node/InterfaceNode/*.vm 

File: templates/Node/InterfaceNode/Type.cpp.vm
        templateFileName
        this.Name

File: templates/Node/InterfaceNode/Type.h.vm
        $OMname
        $templateFileName
        $this.Name
        $this.Name.toPath( 0 args )
        $this.isClass( 0 args )
        $util.toDefineName( 1 args )
        OMname
        this.Name.Base
        util.toDefineName( 1 args )

File: templates/Node/InterfaceNode/Type.i.vm
        $templateFileName
        $this.Name
        $this.Name.toQualifiedName( 0 args )


Summary: 
        $OMname
        $templateFileName
        $this.Name
        $this.Name.toPath( 0 args )
        $this.isClass( 0 args )
        $this.Name.toQualifiedName( 0 args )
        $util.toDefineName( 1 args )
        OMname
        this.Name
        this.Name.Base
        util.toDefineName( 1 args )



On Thu, 2003-02-06 at 15:23, Marvin Greenberg wrote:
> I've made some minor changes to the template tool.  I got rid of the stuff
> that listed every (including repeat) reference, and changed it so that
> references are listed in a sorted order, and that a summary for all the
> template files is also generated.  I also plan to add an option to make all
> equivalent forms show up only once -- $class.Name and ${class.Name} and
> $class.getName(), and compress methods references to only the name and arg
> count.  Beyond that  I was thinking about a doclet to generate a bean
> description from a java class or set of classes (something exists perhaps?),
> which could then be used to actually validate the templates.

---------------------------------------------------------------------------
/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software
itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "The Jakarta Project", "Velocity", and "Apache Software
 *    Foundation" must not be used to endorse or promote products
derived
 *    from this software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

import java.util.ArrayList;
import java.util.TreeSet;
import java.util.Set;
import java.util.List;
import java.util.Iterator;
import java.io.File;

import org.apache.velocity.Template;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.parser.node.SimpleNode;
import org.apache.velocity.runtime.parser.node.ASTReference;
import org.apache.velocity.runtime.visitor.BaseVisitor;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.runtime.parser.ParserConstants;
import org.apache.velocity.runtime.parser.Token;

/**
 *
 * @author <a href="mailto:[EMAIL PROTECTED]">Geir Magnusson Jr.</a>
 * @author Marvin Greenberg
 * @version $Id: $
 */
public class TemplateTool
{
    /** List references in template refered to by file referred to by
String fn */
    public TemplateTool( VelocityEngine ve, String fn )
        throws Exception
    {
            this( ve.getTemplate( fn ) );
    }

    public TemplateTool( Template t ) {
        _template = t;
    }

    /* returns null if no valid template */
    public Set getReferences() {
        if (null == _template)
            return null;

        SimpleNode sn = (SimpleNode) _template.getData();
        ReferenceListVisitor rlv = new ReferenceListVisitor();
        sn.jjtAccept( rlv, null );
        return rlv.getReferences();
    }

    private Template _template;

    public static void usage() {
        System.err.println("java TemplateTool [-s | --summarize]
templatefile...");
        System.exit(1);
    }

    public static void main( String args[] )
        throws Exception
    {
        List files = new ArrayList();
        boolean summarize = false;
        boolean error = false;
        for (int i=0; i<args.length; ++i) {
            if ("-s".equals(args[i]) ||
                "--summarize".equals(args[i])) {
                summarize = true;
            }
            else {
                File f = new File(args[i]);
                if (f.isFile())
                    files.add(args[i]);
                else {
                    System.err.println("Ignored: " + args[i] + ":
invalid flag or nonexistent file");
                    error = true;
                }
            }
        }
        if (error) usage();

        VelocityEngine ve = new VelocityEngine();
        ve.init();

        Set summary = new TreeSet();
        for (Iterator fiter = files.iterator();
             fiter.hasNext();
             )
        {
            String fn = (String)fiter.next();
            try {
                Set refs = (new TemplateTool( ve, fn )).getReferences();

                if (!summarize) {
                    System.out.println("\nFile: " + fn );
                    for (Iterator iter = refs.iterator();
                         iter.hasNext();
                         )
                        {
                            System.out.println("\t" + iter.next() );
                        }
                }
                
                summary.addAll( refs );
            }
        
            catch (Exception e) {
                System.err.println("In " + fn + ":\n" + e);
            }
        }

        /* Summarize if there was more than one template */
        if (files.size() > 1) {
            System.out.println("\n\nSummary: " );
            for (Iterator iter = summary.iterator();
                 iter.hasNext();
                 )
            {
                    System.out.println("\t" + iter.next() );
            }
        }
    }


    /**
     *  Visitor to accumulate references.
     */
    class ReferenceListVisitor extends BaseVisitor
    {
        Set _refset = null;

        ReferenceListVisitor()
        {
            _refset = new TreeSet(); // So references get expected
ordering
        }

        public Set getReferences()
        {
            return _refset;
        }
        /** handle the resolution of arguments into an arg count, and
         * resolve getProperty( 0 args ) to Property.  Similarly should
         * change setProperty( 1 args ) to Property = , but there are
unresolved
         * issues about this since aren't reporting other assignments
yet...
         *
         * @param boolean isMethod True if processing a method token
         * @param Token[] tokenRef Use a 1 element array to allow
modification of the tokenRef
         * @param Token   the last Token that is part of the current
expression
         */

        private StringBuffer handleExpression ( boolean isMethod,
Token[] tokenRef, Token lastToken) {

           Token name = null;
           if (isMethod) {
             name = tokenRef[0];
             tokenRef[0] = tokenRef[0].next;
           }

           StringBuffer sb = new StringBuffer();

           boolean nodeConsumed = false;
           int argCount = 0;
           int discardAll = 0;  // throw away contents of arrays -- just
count as an argument

           for (;
                tokenRef[0] != null && ! nodeConsumed;
                tokenRef[0] = tokenRef[0].next
                )
           {
               switch (tokenRef[0].kind) {
               case ParserConstants.LBRACKET:
                   if (isMethod && discardAll==0)
                       ++ argCount;
                   
                   ++discardAll;
                   break;

               case ParserConstants.RBRACKET:
                   --discardAll;
                   break;
                   
               case ParserConstants.LPAREN:
               case ParserConstants.LCURLY:
               case ParserConstants.RCURLY:
               case ParserConstants.DOLLAR:
               case ParserConstants.DOLLARBANG:
               case ParserConstants.COMMA:

                 /* do nothing - discard redundant syntax */
                 break;

               case ParserConstants.DOT:
                   if (0 == discardAll) 
                       sb.append( '.' );
                   break;

               case ParserConstants.STRING_LITERAL:
                   if (0 == discardAll) {
                       if (isMethod)
                           ++ argCount;
                   }
                   break;

               case ParserConstants.IDENTIFIER:
                   if (0 == discardAll) {
                       if (isMethod)
                           ++argCount;

                       // recurse for a method call, so arg count is not
messed up
                       if (tokenRef[0].next != null &&
                           tokenRef[0].next.kind ==
ParserConstants.LPAREN) {
                           // handle nested method calls, but just throw
away results
                           // except at top, since only care about arg
count.
                           // These calls will/should get visited
themselves later...
                           StringBuffer methodRef =
handleExpression(true, tokenRef, lastToken);
                           if (!isMethod)
                               sb.append(methodRef);
                           
                       }
                       else { // append plain reference
                           sb.append(tokenRef[0].image);
                       }
                   }
                   break;

                 // rparen means return from recursion
                 // For some reason not just RPAREN...
               case ParserConstants.REFMOD2_RPAREN:
                   if (0 == discardAll) {
                       if (isMethod) {
                           if (argCount == 0 &&
name.image.startsWith("get") &&
                               name.image.length() > 3)
                               sb.append(name.image.substring(3));
                           else
                               sb.append(name.image);
                           
                           sb.append("( ").append(argCount).append("
args )");
                           
                           return sb;
                       }
                   }
                   break;
                   

               default:
                   System.err.println("Discarding some unexpected
syntax: " + tokenRef[0].image);
             }

             nodeConsumed = (tokenRef[0] == lastToken);
           }
           return sb;
        }

        public Object visit( ASTReference node, Object data)
        {
          Token lastToken = node.getLastToken();
          Token[] tokenRef = new Token[] { node.getFirstToken() };

          _refset.add( handleExpression( false, tokenRef, lastToken
).toString() );

          data = node.childrenAccept(this, data);

          return data;
        }
    }

}




---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to