Generator.java :  » IDE-Netbeans » i18n » org » netbeans » modules » i18n » regexp » Java Open Source

Java Open Source » IDE Netbeans » i18n 
i18n » org » netbeans » modules » i18n » regexp » Generator.java
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common
 * Development and Distribution License("CDDL") (collectively, the
 * "License"). You may not use this file except in compliance with the
 * License. You can obtain a copy of the License at
 * http://www.netbeans.org/cddl-gplv2.html
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
 * specific language governing permissions and limitations under the
 * License.  When distributing the software, include this License Header
 * Notice in each file and include the License file at
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the GPL Version 2 section of the License file that
 * accompanied this code. If applicable, add the following below the
 * License Header, with the fields enclosed by brackets [] replaced by
 * your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * Contributor(s):
 *
 * The Original Software is NetBeans. The Initial Developer of the Original
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
 * Microsystems, Inc. All Rights Reserved.
 *
 * If you wish your version of this file to be governed by only the CDDL
 * or only the GPL Version 2, indicate your decision by adding
 * "[Contributor] elects to include this software in this distribution
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
 * single choice of license, a recipient has the option to distribute
 * your version of this file under either the CDDL, the GPL Version 2 or
 * to extend the choice of license to its licensees as provided above.
 * However, if you add GPL Version 2 code and therefore, elected the GPL
 * Version 2 license, then the option applies only if the new code is
 * made subject to such option by the copyright holder.
 */


package org.netbeans.modules.i18n.regexp;

import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Generator of JDK regular expressions from syntax trees.
 * It accepts a syntax tree of a regular expression and generates a regular
 * expression according to syntax rules of JDK's class
 * {@link java.util.regex.Pattern Pattern}.
 *
 * @author  Marian Petras
 */
class Generator {

    /** buffer where the regular expression is being built */
    private StringBuilder buf = new StringBuilder(20);

    /** string to put in place of tokens */
    private Map<String,String> tokenReplacements;

    /** */
    private boolean generatingSetOfChars = false;


    /**
     * Generates a regular expression from a syntax tree.
     *
     * @param  parseTree  root of a syntax tree to create a regular expression
     *                    from 
     * @return  generated regular expression;
     *          or <code>null</code> if the argument was <code>null</code>
     */
    public static String generateRegexp(TreeNode parseTree) {
        return generateRegexp(parseTree, null);
    }


    /**
     * Generates a regular expression from a syntax tree.
     *
     * @param  parseTree  root of a syntax tree to create a regular expression
     *                    from 
     * @param  tokenReplacements  maps token names to strings to be put in place
     *                            of them, or <code>null</code> to ignore tokens
     * @return  generated regular expression;
     *          or <code>null</code> if the argument was <code>null</code>
     */
    public static String generateRegexp(TreeNode parseTree, Map<String,String> tokenReplacements) {
        if (parseTree == null) {
            return null;
        }

        Generator g = new Generator();
        g.setTokenReplacements(tokenReplacements);
        g.generate(parseTree);
        return g.buf.toString();
    }


    /** */
    private static String quoteString(String string) {
        if (string.length() == 0) {
            return string;
        }

        StringBuilder buf;

        int startIndex = 0;
        int endIndex = string.indexOf('\\');                           //NOI18N

        if (endIndex == -1) {
            buf = new StringBuilder(string.length() + 4);
            buf.append("\\Q").append(string).append("\\E");             //NOI18N
        } else {
            buf = new StringBuilder(string.length() + 16);
            do {
                if (endIndex != startIndex) {
                    buf.append("\\Q");                                  //NOI18N
                    buf.append(string.substring(startIndex, endIndex));
                    buf.append("\\E");                                  //NOI18N
                }
                buf.append('\\').append('\\');                                    //NOI18N
                startIndex = endIndex + 1;
                endIndex = string.indexOf('\\', startIndex);           //NOI18N
            } while (endIndex != -1);
            if (startIndex != string.length()) {
                buf.append("\\Q");                                      //NOI18N
                buf.append(string.substring(startIndex));
                buf.append("\\E");                                      //NOI18N
            }
        }
        return buf.toString();
    }


    /** */
    private void setTokenReplacements(Map<String,String> tokenReplacements) {
        if ((tokenReplacements != null) && tokenReplacements.isEmpty()) {
            tokenReplacements = null;
        }
        this.tokenReplacements = tokenReplacements;

        if (tokenReplacements != null) {
            quoteTokenReplacements();
        }
    }


    /** */
    private void quoteTokenReplacements() {
        if (tokenReplacements == null || tokenReplacements.isEmpty()) {
            return;
        }

        for (Map.Entry<String,String> entry : tokenReplacements.entrySet()) {
            entry.setValue(quoteString(entry.getValue()));
        }
    }


    /** */
    private void generate(TreeNode treeNode) {
        List<TreeNode> children = treeNode.getChildren();
        int tokenType = treeNode.getTokenType();
        Object attribs = treeNode.getAttribs();
        char charType;
        switch (tokenType) {
            case TreeNode.CHAR:
                char ch = ((Character) attribs).charValue();
                switch (ch) {
                    case '\t':
                        buf.append('\\').append('t');
                        break;

                    case '\n':
                        buf.append('\\').append('n');
                        break;

                    case '\r':
                        buf.append('\\').append('r');
                        break;

                    case '\f':
                        buf.append('\\').append('f');
                        break;

                    case '\\':
                        buf.append('\\').append('\\');
                        break;

                    default:
                        if (!generatingSetOfChars
                               && ("^$|*+?.()[]{}".indexOf(ch) != -1)) {//NOI18N
                            buf.append('\\');
                        }
                        buf.append(ch);
                        break;
                }
                break;

            case TreeNode.METACHAR:
                charType = ((Character) attribs).charValue();
                if (charType == '.') {
                    buf.append('.');
                } else {
                    buf.append('\\').append(charType);            //    \b or \B
                }
                break;

            case TreeNode.QUANTIFIER:
                if (attribs instanceof Character) {
                    charType = ((Character) attribs).charValue();
                    buf.append(charType);
                } else {
                    String type = (String) attribs;
                    buf.append('{');
                    generate(children.get(0));             //Integer - low limit
                    if (type.length() > 3) {               //"{n,}" or "{n,n}"
                        buf.append(',');
                        if (type.length() == 5) {          //"{n,n}"
                            generate(children.get(1));     //- high limit
                        }
                    }
                    buf.append('}');
                }
                break;

            case TreeNode.Q_REGEXP:
                generate(children.get(0));
                if (children.size() == 2) {
                    generate(children.get(1));
                }
                break;

            case TreeNode.RANGE:
                generate(children.get(0));
                buf.append('-');
                generate(children.get(1));
                break;

            case TreeNode.SET:
                buf.append('[');
                if (attribs != null) {
                    buf.append((String) attribs);
                }
                if (children != null) {
                    generatingSetOfChars = true;
                    if (children.size() == 1) {
                        generate(children.get(0));
                    } else {
                        for (TreeNode child : children) {
                            generate(child);
                        }
                    }
                    generatingSetOfChars = false;
                }
                buf.append(']');
                break;

            case TreeNode.SIMPLE_REGEXP:
                if (children != null) {
                    if (children.size() == 1) {
                        generate(children.get(0));
                    } else {
                        for (TreeNode child : children) {
                            generate(child);
                        }
                    }
                }
                break;

            case TreeNode.SUBEXPR:
                buf.append('(').append('?').append(':');
                generate(children.get(0));
                buf.append(')');
                break;

            case TreeNode.MULTI_REGEXP:
                generate(children.get(0));
                if (children.size() > 1) {
                    Iterator<TreeNode> i = children.iterator();
                    i.next();                               //skip the first one
                    do {
                        buf.append('|');
                        generate(i.next());
                    } while (i.hasNext());
                }
                break;

            case TreeNode.NUMBER:
                buf.append(attribs.toString());
                break;

            case TreeNode.UNICODE_CHAR:
                int code = ((Integer) attribs).intValue();
                buf.append((char) code);
                break;

            case TreeNode.POSIX_SET:
                buf.append('\\').append('p');
                buf.append('{');
                String className = (String) attribs;
                if (className.equals("ascii")) {                        //NOI18N
                    buf.append("ASCII");                                //NOI18N
                } else if (className.equals("xdigit")) {                //NOI18N
                    buf.append("XDigit");                               //NOI18N
                } else {
                    buf.append(Character.toUpperCase(className.charAt(0)));
                    buf.append(className.substring(1));
                }
                buf.append('}');
                break;

            case TreeNode.REGEXP:
                String attrString = (String) attribs;
                if (attrString != null && attrString.charAt(0) == '^') {
                    buf.append('^');
                }
                if (children != null) {
                    generate(children.get(0));
                }
                if (attrString != null && (attrString.length() == 2
                                           || attrString.charAt(0) == '$')) {
                    buf.append('$');
                }
                break;

            case TreeNode.TOKEN:
                String tokenName = (String) attribs;
                String replacement = tokenReplacements != null
                                     ? tokenReplacements.get(tokenName)
                                     : null;
                if (replacement != null) {
                    buf.append('(').append('?').append(':');
                    buf.append(replacement);
                    buf.append(')');
                } else {
                    buf.append('{').append(tokenName).append('}');
                }
                break;

            default:
                assert false;
                break;
        }
    }

}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.