alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 *
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 *
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.editor.ext.java;

import java.util.*;
import javax.swing.text.BadLocationException;
import org.netbeans.editor.TokenContextPath;
import org.netbeans.editor.TokenID;
import org.netbeans.editor.ext.ExtSyntaxSupport;
import org.openide.ErrorManager;


/**
* Support methods for syntax analyzes working with java JMI interfaces.
*
* @author Dusan Balek, Martin Roskanin
* @version 1.00
*/
class JavaDeclarationProcessor
implements ExtSyntaxSupport.DeclarationTokenProcessor,
ExtSyntaxSupport.VariableMapTokenProcessor {
    
    // Internal java declaration token processor states (in the state variable
    private static final int INIT = 0; // nothing recognized yet
    private static final int TYPE_VAR = 1; // initial datatype or variable already recognized
    private static final int TYPE_EXP = 2; // active type expression recognition in progress
    private static final int VAR_EXP = 3; // active variable declaration in progress
    private static final int EQ_EXP = 4; // "type var = " was recognized and now in after "=" exp
    
    
    // JCExpression constants
    private static final int VARIABLE = JCExpression.VARIABLE;
    private static final int DOT = JCExpression.DOT;
    private static final int DOT_OPEN = JCExpression.DOT_OPEN;
    private static final int ARRAY_OPEN = JCExpression.ARRAY_OPEN;
    private static final int ARRAY = JCExpression.ARRAY;
    private static final int PARENTHESIS_OPEN = JCExpression.PARENTHESIS_OPEN;
    private static final int PARENTHESIS = JCExpression.PARENTHESIS;
    private static final int TYPE = JCExpression.TYPE;
    private static final int GENERIC_TYPE = JCExpression.GENERIC_TYPE;
    private static final int GENERIC_TYPE_OPEN = JCExpression.GENERIC_TYPE_OPEN;

    // Invlaid value marking no expression on the given stack position for peekExp()
    private static final int NO_EXP = -1;

    /** Internal state of recognition engine. */
    private int state;
    
    /** Stack of the expressions related to declarations recognition. */
    private List expStack = new ArrayList();
    
    /** Type expression of the declaration being recognized. */
    private JCExpression typeExp;
    
    /** Support backing this declaration recognizer. */
    private JavaSyntaxSupport sup;
    
    /** Position of the begining of the declaration to be returned */
    private int decStartPos = -1;
    
    /**
     * Absolute offset of the initial variable or type name of declaration.
     * The appropriate JCExpression gets created later
     * once another token gets recognized and there
     * is still a probability that a real declaration was found.
     */
    private int typeVarTokenOffset;

    /**
     * Length of the initial variable or type name. The appropriate JCExpression
     * gets created later once another token gets recognized and there
     * is still a probability that a real declaration was found.
     */
    private int typeVarTokenLength;
    
    /**
     * State whether the initial variable is a primitive datatype.
     */
    private TokenID typeVarTokenID;
    
    /** Currently inside parenthesis, i.e. comma delimits declarations */
    private int parenDepth;
    
    private TokenID curTokenID;
    private int curTokenPosition;
    private int curTokenLength;
    private char[] buffer;
    
    private int bufferStartPos;
    
    /** Variable name to be recognized when operating in a single variable mode. */
    private String varName;
    
    /** 
     * Map filled with the [varName, TypeResolver] pairs.
     */
    private StackedMap varMap;

    private boolean forScope;
    private int forScopeParenDepth;


    /** Construct new token processor
     * @param varName it contains valid varName name or null to search
     *   for all variables and construct the variable map.
     */
    JavaDeclarationProcessor(JavaSyntaxSupport sup, String varName) {
        this.sup = sup;
        this.varName = varName;
        if (varName == null) {
            varMap = new StackedMap();
        }
    }
    
    /**
     * Return integer offset corresponding to the begining
     * of the declaration of the requested variable name.
     */
    public int getDeclarationPosition() {
        return decStartPos;
    }

    /**
     * Return map containing [varName, JavaSyntaxSupport.JavaVariable] pairs
     * where typeResolver allows lazy resolving of the variable's type
     * by using {@link #resolveType(Object)}.
     */
    public Map getVariableMap() {
        return varMap;
    }
    
    private void clearStack() {
        expStack.clear();
    }

    /** Push exp to top of stack */
    private void pushExp(JCExpression exp) {
        expStack.add(exp);
    }

    /** Pop exp from top of stack */
    private JCExpression popExp() {
        int cnt = expStack.size();
        return (cnt > 0) ? (JCExpression)expStack.remove(cnt - 1) : null;
    }

    /** Look at the exp at top of stack */
    private JCExpression peekExp() {
        int cnt = expStack.size();
        return (cnt > 0) ? (JCExpression)expStack.get(cnt - 1) : null;
    }

    /** Look at the second exp on stack */
    private JCExpression peekExp2() {
        int cnt = expStack.size();
        return (cnt > 1) ? (JCExpression)expStack.get(cnt - 2) : null;
    }

    /** Look at the third exp on stack */
    private JCExpression peekExp(int ind) {
        int cnt = expStack.size();
        return (cnt >= ind) ? (JCExpression)expStack.get(cnt - ind) : null;
    }

    private JCExpression createTokenExp(int id) {
        JCExpression exp = new JCExpression(id);
        addTokenTo(exp);
        return exp;
    }

    /** Add the token to a given expression */
    private void addTokenTo(JCExpression exp) {
        exp.addToken(curTokenID, curTokenPosition, getTokenText(curTokenPosition, curTokenLength));
    }
    
    private int getValidExpID(JCExpression exp) {
        return (exp != null) ? exp.getExpID() : NO_EXP;
    }
    
    private void pushTypeVar() {
        if (state != TYPE_VAR) {
            throw new IllegalArgumentException();
        }

        state = TYPE_EXP; // var or type will be pushed to stack
        int expType;
        TokenID id;
        if (typeVarTokenID != null) {
            expType = JCExpression.TYPE;
            id = typeVarTokenID;

        } else { // Variable
            expType = JCExpression.VARIABLE;
            id = JavaTokenContext.IDENTIFIER;
        }

        JCExpression exp = new JCExpression(expType);
        exp.addToken(id, typeVarTokenOffset,
            getTokenText(typeVarTokenOffset, typeVarTokenLength));
        pushExp(exp); // push initial exp on the stack
    }
    
    private void reset() {
        state = INIT;
        clearStack();
        typeExp = null;
    }
    
    /**
     * Form the type expression.
     *
     * @return true if the expression was formed successfully
     *  or false if not (reset() will be called in that case).
     */
    private boolean formTypeExp() {
        if (expStack.size() == 1) { // must be exactly one exp on stack
            typeExp = popExp();
            switch (typeExp.getExpID()) {
                case ARRAY_OPEN:
                case DOT_OPEN:
                    reset();
                    return false;
                    
                default:
                    state = VAR_EXP; // start forming variable expression
                    return true;
            }
            
        } else { // more than one exp on stack -> incomplete exp
            reset();
            return false;
        }
    }
    
    /**
     * Create variable expression.
     *
     * @param lastVar true if this formed variable is the last one
     *  (is followed e.g. by semicolon) or whether there can be more variables
     *  (such as after comma) which will assign TYPE_EXP state.
     *
     * @return true if variable expression formed successfully
     *  from the information on the stack
     *  or false if not (reset() will be called in that case).
     */
    private boolean formVarExp(boolean lastVar) {
        JCExpression varExp;
        if (expStack.size() == 1) { // must be exactly one exp on stack
            // leave state == VAR_EXP
            varExp = popExp(); // stack will be empty
            if (varExp != null) { // formed successfully
                switch (varExp.getExpID()) {
                    case VARIABLE:
                    case ARRAY:
                        break; // leave varExp assigned to non-null
                        
                    default:
                        varExp = null;
                        break;
                }
            }
            
        } else { // more than one exp on stack -> incomplete exp
            varExp = null;
        }
            
        if (varExp != null) {
            processDeclaration(typeExp, varExp);
            if (lastVar) {
                reset();
            } else { // not last var
                // Continue to be in VAR_EXP state
                // Stack already empty from previous popExp()
            }
            return true;

        } else {
            reset();
            return false;
        }
    }
    
    private String getTokenText(int offset, int length) {
        try {
            return sup.getDocument().getText(offset, length);
        } catch (BadLocationException e) {
            ErrorManager.getDefault().notify(e);
            return "";
        }
    }

    private void processDeclaration(JCExpression typeExp, JCExpression varExp) {
        if (varName == null) { // collect all variables
            String varName = getVarName(varExp);
            JavaVar javaVar = new JavaVar(typeExp, varExp);
            varMap.put(varName, javaVar);
            
        } else if (varName.equals(getVarName(varExp))) { // found var of the requested name
            decStartPos = typeVarTokenOffset;
        }
    }
    
    private String getVarName(JCExpression varExp) {
        switch (varExp.getExpID()) {
            case VARIABLE:
                return varExp.getTokenText(0);
                
            case ARRAY:
                JCExpression var = varExp.getParameter(0); // variable of the array
                return var.getTokenText(0);
                
            default:
                throw new IllegalStateException();
        }
    }
    
    public boolean token(TokenID tokenID, TokenContextPath tokenContextPath,
    int tokenOffset, int tokenLen) {
        int pos = bufferStartPos + tokenOffset;
        
        curTokenID = tokenID;
        curTokenPosition = pos;
        curTokenLength = tokenLen;
        
        // Check whether we are really recognizing the java tokens
        if (!tokenContextPath.contains(JavaTokenContext.contextPath)) {
            state = INIT;
            return true;
        }
        
        switch (tokenID.getNumericID()) {
            case JavaTokenContext.BOOLEAN_ID:
            case JavaTokenContext.BYTE_ID:
            case JavaTokenContext.CHAR_ID:
            case JavaTokenContext.DOUBLE_ID:
            case JavaTokenContext.FLOAT_ID:
            case JavaTokenContext.INT_ID:
            case JavaTokenContext.LONG_ID:
            case JavaTokenContext.SHORT_ID:
                if (parenDepth <= 1) { // no parens or in method declaration parms
                    switch (state) {
                        case INIT:
                            typeVarTokenOffset = pos;
                            typeVarTokenLength = tokenLen;
                            typeVarTokenID = tokenID;
                            state = TYPE_VAR;
                            break;

                        case TYPE_VAR: // var-or-type type => invalid
                        case TYPE_EXP: // something followed by datatype => invalid
                        case VAR_EXP: // varName followed by datatype => invalid
                            reset();
                            break;

                        case EQ_EXP: // in expression after "type var = "
                            // do nothing - leave the EQ_EXP state
                            break;

                        default:
                            throw new IllegalStateException();
                    }
                } // else -> in parens -> do nothing
                break;

            case JavaTokenContext.FOR_ID:
                if (varMap != null) {
                    varMap.pushNewScope();
                    forScope = true;
                }
                break;

            case JavaTokenContext.IDENTIFIER_ID:
                if (parenDepth <= 1) { // no parens or in method declaration parms
                    switch (state) {
                        case INIT:
                            typeVarTokenOffset = pos;
                            typeVarTokenLength = tokenLen;
                            typeVarTokenID = null;
                            state = TYPE_VAR;
                            break;

                        case TYPE_VAR: // var-or-type ident => maybe declaration
                            pushTypeVar();
                            // continue to TYPE_EXP handling
                        case TYPE_EXP: // something followed by ident => varName
                            JCExpression top = peekExp();
                            switch (getValidExpID(top)) {
                                case VARIABLE: // var "ident" -> decl
                                case TYPE: // "int" "ident" -> decl
                                case DOT: // var1.var2. ... var-n "ident"
                                case ARRAY: // "array[]" "ident"
                                case GENERIC_TYPE: // List "ident"
                                    if (formTypeExp()) { // formed successfully
                                        // start to form variable expression
                                        pushExp(createTokenExp(VARIABLE));
                                    }
                                    break;

                                case DOT_OPEN: // closing dot expr.
                                    top.setExpID(DOT);
                                    top.addParameter(createTokenExp(VARIABLE));
                                    break;

                                case GENERIC_TYPE_OPEN: // 
                                    pushExp(createTokenExp(VARIABLE));
                                    break;

                                default:
                                    reset();
                                    break;
                            }
                            break;

                        case VAR_EXP: // unclosed var decl. followed by ident -> invalid
                            if (expStack.size() == 0) { // nothing on stack
                                // This can happen after comma that was separating
                                // two variables of the same type
                                pushExp(createTokenExp(VARIABLE));

                            } else { // invalid "var" "var" (or e.g. "var[]" "var")
                                reset();
                            }
                            break;

                        case EQ_EXP: // in expression after "type var = "
                            // do nothing - leave the EQ_EXP state
                            break;

                        default:
                            throw new IllegalStateException();
                    }
                } // else -> in parens -> do nothing
                break;

                
            case JavaTokenContext.DOT_ID:
                if (parenDepth <= 1) { // no parens or in method declaration parms
                    switch (state) {
                        case INIT: // dot in initial state -> do nothing
                            break;

                        case TYPE_VAR: // var-or-type "." -> open dot
                            pushTypeVar();
                            // continue to TYPE_EXP handling
                        case TYPE_EXP:
                            JCExpression top = peekExp();
                            switch (getValidExpID(top)) {
                                case VARIABLE: // var "." -> DOT_OPEN
                                case GENERIC_TYPE: // "C1.C2" -> DOT_OPEN
                                    popExp(); // pop var
                                    JCExpression opExp = createTokenExp(DOT_OPEN);
                                    opExp.addParameter(top);
                                    pushExp(opExp);
                                    break;

                                case DOT: // var1.var2. ... var-n "."
                                    top.setExpID(DOT_OPEN);
                                    break;

                                default:
                                    reset();
                                    break;
                            }
                            break;
                            
                        case VAR_EXP: // "type var." -> reset
                            reset();
                            break;

                        case EQ_EXP: // in expression after "type var = "
                            // do nothing - leave the EQ_EXP state
                            break;

                        default:
                            throw new IllegalStateException();
                    }
                } // else -> in parens -> do nothing
                break;


            case JavaTokenContext.LBRACKET_ID: // "["
                if (parenDepth <= 1) { // no parens or in method declaration parms
                    switch (state) {
                        case INIT: // '[' in initial state -> do nothing
                            break;

                        case TYPE_VAR: // var-or-type "[" -> open array
                            pushTypeVar();
                            // continue to TYPE_EXP handling
                        case TYPE_EXP:
                            {
                                JCExpression top = peekExp();
                                switch (getValidExpID(top)) {
                                    case DOT: // var1.var2. ... var-n "["
                                    case VARIABLE: // var "[" -> ARRAY_OPEN
                                    case TYPE:
                                    case GENERIC_TYPE: // e.g. "List" "[" -> ARRAY_OPEN
                                        popExp(); // pop var
                                        JCExpression opExp = createTokenExp(ARRAY_OPEN);
                                        opExp.addParameter(top);
                                        pushExp(opExp);
                                        break;

                                    case ARRAY: // array[] "[" -> sub-ARRAY_OPEN again
                                        top.setExpID(ARRAY_OPEN);
                                        addTokenTo(top);
                                        break;

                                    default:
                                        reset();
                                        break;
                                }
                                break;
                            }

                        case VAR_EXP: // e.g. "int a" "[" -> ARRAY_OPEN
                            {
                                JCExpression top = peekExp();
                                switch (getValidExpID(top)) {
                                    case VARIABLE: // var "[" -> ARRAY_OPEN
                                        popExp(); // pop var
                                        JCExpression opExp = createTokenExp(ARRAY_OPEN);
                                        opExp.addParameter(top);
                                        pushExp(opExp);
                                        break;

                                    case ARRAY: // array[] "[" -> sub-ARRAY_OPEN again
                                        top.setExpID(ARRAY_OPEN);
                                        addTokenTo(top);

                                    default:
                                        reset();
                                        break;
                                }
                                break;
                            }

                        case EQ_EXP: // in expression after "type var = "
                            // do nothing - leave the EQ_EXP state
                            break;

                        default:
                            throw new IllegalStateException();
                    }
                } // else -> in parens -> do nothing
                break;

            case JavaTokenContext.ELLIPSIS_ID: // "..."
                if (parenDepth <= 1) { // no parens or in method declaration parms
                    switch (state) {
                        case INIT: // '[' in initial state -> do nothing
                            break;

                        case TYPE_VAR: // var-or-type "..." -> array
                            pushTypeVar();
                            // continue to TYPE_EXP handling
                        case TYPE_EXP:
                            {
                                JCExpression top = peekExp();
                                switch (getValidExpID(top)) {
                                    case DOT: // var1.var2. ... var-n "..." -> ARRAY
                                    case VARIABLE: // var "..." -> ARRAY
                                    case TYPE: // int "..." -> ARRAY
                                    case GENERIC_TYPE: // e.g. "List" "..." -> ARRAY
                                        popExp(); // pop var
                                        JCExpression opExp = createTokenExp(ARRAY);
                                        // Add "..." again to have the even token count like with "[" "]"
                                        addTokenTo(opExp);
                                        opExp.addParameter(top);
                                        pushExp(opExp);
                                        break;

                                    case ARRAY: // array[] "[" -> sub-ARRAY_OPEN again
                                        addTokenTo(top);
                                        // Add "..." again to have the even token count like with "[" "]"
                                        addTokenTo(top);
                                        break;

                                    default:
                                        reset();
                                        break;
                                }
                                break;
                            }

                        case VAR_EXP: // e.g. "int a" "..." -> ARRAY_OPEN
                            reset();
                            break;

                        case EQ_EXP: // in expression after "type var = "
                            // do nothing - leave the EQ_EXP state
                            break;

                        default:
                            throw new IllegalStateException();
                    }
                } // else -> in parens -> do nothing
                break;


            case JavaTokenContext.RBRACKET_ID: // "]"
                if (parenDepth <= 1) { // no parens or in method declaration parms
                    switch (state) {
                        case INIT: // ']' in initial state -> do nothing
                            break;

                        case TYPE_VAR: // var-or-type "]" -> error
                            reset();
                            break;

                        case TYPE_EXP:
                            {
                                JCExpression top = peekExp();
                                switch (getValidExpID(top)) {
                                    case ARRAY_OPEN: // "type[" "]" -> ARRAY
                                        addTokenTo(top);
                                        top.setExpID(ARRAY);
                                        break;

                                    default:
                                        reset();
                                        break;
                                }
                                break;
                            }

                        case VAR_EXP: // e.g. "int a[" "]" -> ARRAY
                            {
                                JCExpression top = peekExp();
                                switch (getValidExpID(top)) {
                                    case ARRAY_OPEN: // type var[ "]" -> ARRAY
                                        addTokenTo(top);
                                        top.setExpID(ARRAY);
                                        break;

                                    default:
                                        reset();
                                        break;
                                }
                                break;
                            }

                        case EQ_EXP: // in expression after "type var = "
                            // do nothing - leave the EQ_EXP state
                            break;

                        default:
                            throw new IllegalStateException();
                    }
                } // else -> in parens -> do nothing
                break;


            case JavaTokenContext.LT_ID: // "<"
                {
                    if (parenDepth <= 1) { // no parens or in method declaration parms
                        switch (state) {
                            case TYPE_VAR:
                                pushTypeVar();
                                // continue to TYPE_EXP handling
                            case TYPE_EXP:
                                JCExpression top = peekExp();
                                switch (getValidExpID(top)) {
                                    case VARIABLE:
                                    case DOT:
                                        popExp(); // pop the top expression
                                        JCExpression genExp = createTokenExp(GENERIC_TYPE_OPEN);
                                        genExp.addParameter(top);
                                        pushExp(genExp);
                                        break;
                                        
                                    default:
                                        // could possibly still be acceptable as operator '<'
                                        break;
                                }
                                break;

                            case EQ_EXP: // in expression after "type var = "
                                // do nothing - leave the EQ_EXP state
                                break;
                                
                            default:
                                reset();
                                break;
                        }
                    } // else - inside parens inside the exp after "="
                    break;
                }


            case JavaTokenContext.GT_ID: // ">"
                {
                    if (parenDepth <= 1) { // no parens or in method declaration parms
                        switch (state) {
                            case TYPE_VAR:
                                pushTypeVar();
                                // continue to TYPE_EXP handling
                            case TYPE_EXP:
                                JCExpression top = peekExp();
                                switch (getValidExpID(top)) {
                                    case VARIABLE:
                                    case ARRAY:
                                    case DOT:
                                    case GENERIC_TYPE:
                                        JCExpression top2 = peekExp2();
                                        switch (getValidExpID(top2)) {
                                            case GENERIC_TYPE_OPEN:
                                                popExp(); // pop the top expression
                                                top2.addParameter(top);
                                                top2.setExpID(GENERIC_TYPE);
                                                addTokenTo(top2);
                                                top = top2;
                                                break;
                                                
                                            default:
                                                reset();
                                                break;
                                        }
                                        break;
                                        
                                    default:
                                        reset();
                                        break;
                                }
                                break;

                            case EQ_EXP: // in expression after "type var = "
                                // do nothing - leave the EQ_EXP state
                                break;
                                
                            default:
                                reset();
                                break;
                        }
                    } // else - inside parens inside the exp after "="
                    break;
                }


            case JavaTokenContext.RSSHIFT_ID: // ">>"
                {
                    if (parenDepth <= 1) { // no parens or in method declaration parms
                        switch (state) {
                            case TYPE_VAR:
                                pushTypeVar();
                                // continue to TYPE_EXP handling
                            case TYPE_EXP:
                                JCExpression top = peekExp();
                                switch (getValidExpID(top)) {
                                    case VARIABLE:
                                    case DOT:
                                    case GENERIC_TYPE:
                                        JCExpression top2 = peekExp2();
                                        switch (getValidExpID(top2)) {
                                            case GENERIC_TYPE_OPEN:
                                                // Check whether outer is open as well
                                                JCExpression top3 = peekExp(3);
                                                if (getValidExpID(top3) == GENERIC_TYPE_OPEN) {
                                                    popExp();
                                                    top2.addParameter(top);
                                                    top2.setExpID(GENERIC_TYPE);
                                                    addTokenTo(top2); // [TODO] revise possible spliting of the token
                                                    
                                                    popExp();
                                                    top3.addParameter(top2);
                                                    top3.setExpID(GENERIC_TYPE);
                                                    addTokenTo(top3); // [TODO] revise possible spliting of the token
                                                    
                                                } else { // inner is not generic type
                                                    reset();
                                                }
                                                break;
                                                
                                            default:
                                                reset();
                                                break;
                                        }
                                        break;
                                        
                                    default:
                                        reset();
                                        break;
                                }
                                break;

                            case EQ_EXP: // in expression after "type var = "
                                // do nothing - leave the EQ_EXP state
                                break;
                                
                            default:
                                reset();
                                break;
                        }
                    } // else - inside parens inside the exp after "="
                    break;
                }
                
                
            case JavaTokenContext.RUSHIFT_ID: // ">>>"
                {
                    if (parenDepth <= 1) { // no parens or in method declaration parms
                        switch (state) {
                            case TYPE_VAR:
                                pushTypeVar();
                                // continue to TYPE_EXP handling
                            case TYPE_EXP:
                                JCExpression top = peekExp();
                                switch (getValidExpID(top)) {
                                    case VARIABLE:
                                    case DOT:
                                    case GENERIC_TYPE:
                                        JCExpression top2 = peekExp2();
                                        switch (getValidExpID(top2)) {
                                            case GENERIC_TYPE_OPEN:
                                                // Check whether outer is open as well
                                                JCExpression top3 = peekExp(3);
                                                JCExpression top4 = peekExp(4);
                                                if (getValidExpID(top3) == GENERIC_TYPE_OPEN
                                                && getValidExpID(top4) == GENERIC_TYPE_OPEN
                                                ) {
                                                    popExp();
                                                    top2.addParameter(top);
                                                    top2.setExpID(GENERIC_TYPE);
                                                    addTokenTo(top2); // [TODO] revise possible spliting of the token
                                                    
                                                    popExp();
                                                    top3.addParameter(top2);
                                                    top3.setExpID(GENERIC_TYPE);
                                                    addTokenTo(top3); // [TODO] revise possible spliting of the token
                                                    
                                                    popExp();
                                                    top4.addParameter(top3);
                                                    top4.setExpID(GENERIC_TYPE);
                                                    addTokenTo(top4); // [TODO] revise possible spliting of the token
                                                    
                                                } else { // inner is not generic type
                                                    reset();
                                                }
                                                break;
                                                
                                            default:
                                                reset();
                                                break;
                                        }
                                        break;
                                        
                                    default:
                                        reset();
                                        break;
                                }
                                break;

                            case EQ_EXP: // in expression after "type var = "
                                // do nothing - leave the EQ_EXP state
                                break;
                                
                            default:
                                reset();
                                break;
                        }
                    } // else - inside parens inside the exp after "="
                    break;
                }
                
                
            case JavaTokenContext.LPAREN_ID: // "("
                switch (state) {
                    case TYPE_VAR:
                        pushTypeVar();
                        // continue to TYPE_EXP handling
                    case TYPE_EXP:
                    case VAR_EXP: // unclosed var decl. followed by ident -> invalid
                    case INIT:
                        reset();
                        break;

                    case EQ_EXP: // in expression after "type var = "
                        break;

                    default:
                        throw new IllegalStateException();
                }

                // In all cases increase the parenthesis depth
                parenDepth++;
                if (forScope)
                    forScopeParenDepth++;
                break;
                
            case JavaTokenContext.RPAREN_ID: // ")"
                switch (state) {
                    case TYPE_VAR:
                        pushTypeVar();
                        // continue to TYPE_EXP handling
                    case TYPE_EXP:
                    case INIT:
                        reset();
                        break;

                    case VAR_EXP: // unclosed var decl. followed by ident -> invalid
                        if (parenDepth == 1) { // method declaration end?
                            formVarExp(true);
                        } else {
                            reset();
                        }
                        break;
                        
                    case EQ_EXP: // in expression after "type var = "
                        break;

                    default:
                        throw new IllegalStateException();

                }
                
                // // In all cases decrease the parenthesis depth
                if (parenDepth > 0) {
                    parenDepth--;
                }
                if (forScope && forScopeParenDepth > 0) {
                    forScopeParenDepth--;
                }
                break;


            case JavaTokenContext.LBRACE_ID: // "{" treated as cmd sep.
                reset();
                parenDepth = 0; // Reset the parenthesis depth to zero
                if (!forScope && varMap != null)
                    varMap.pushNewScope();
                forScope = false;
                break;

            case JavaTokenContext.RBRACE_ID: // "}" treated as cmd sep.
                reset();
                parenDepth = 0; // Reset the parenthesis depth to zero
                if (varMap != null)
                    varMap.removeScope();
                break;


            case JavaTokenContext.SEMICOLON_ID: // ';' treated as cmd sep.
                if (forScope && forScopeParenDepth == 0) {
                    if (varMap != null)
                        varMap.removeScope();
                    forScope = false;
                }
                switch (state) {
                    case VAR_EXP:
                        formVarExp(true);
                        break;
                        
                    default:
                        reset();
                        break;
                        
                }
                break;


            case JavaTokenContext.COMMA_ID:
                if (parenDepth <= 1) { // no parens or in method declaration parms
                    switch (state) {
                        case TYPE_EXP:
                            JCExpression top2 = peekExp2();
                            if (getValidExpID(top2) == GENERIC_TYPE_OPEN) {
                                JCExpression top = peekExp();
                                switch (getValidExpID(top)) {
                                    case VARIABLE:
                                    case DOT:
                                    case GENERIC_TYPE:
                                        popExp();
                                        top2.addParameter(top);
                                        addTokenTo(top2); // add "," to open generics type
                                        break;

                                    default:
                                        reset();
                                        break;
                                }

                            } else { // not open generics
                                // and not followed by identifier so it can't be
                                // param separator in parenDepth == 1 as well
                                reset();
                            }
                            break;

                        case VAR_EXP:
                            // can either be "int var1, var2" or m1(int i, String s)
                            formVarExp(parenDepth == 1);
                            break;
                            
                        case EQ_EXP: // in expression after "type var = "
                            if (parenDepth == 0) { // separates variable expressions
                                state = VAR_EXP; // expect next variable
                            } // else - commas e.g. in "type var = method(a, b, c)" => do nothing
                            break;

                        default:
                            reset();
                            break;
                    }
                    
                } // else -> in parens -> do nothing
                break;
                
                
            case JavaTokenContext.EQ_ID:
                if (parenDepth <= 1) {
                    switch (state) {
                        case VAR_EXP:
                            formVarExp(false);
                            state = EQ_EXP;
                            break;
                            
                        case EQ_EXP: // in expression after "type var = "
                            // do nothing - leave the EQ_EXP state
                            break;

                        default:
                            reset();
                            break;
                    }
                } // else -> in parens -> do nothing
                break;

                
            case JavaTokenContext.WHITESPACE_ID: // whitespace ignored
            case JavaTokenContext.LINE_COMMENT_ID: // line comment ignored
            case JavaTokenContext.BLOCK_COMMENT_ID: // block comment ignored
                break;
                        
            case JavaTokenContext.COLON_ID: // 1.5 enhanced for loop sysntax
                if (parenDepth <= 1) {
                    switch (state) {
                        case VAR_EXP:
                            formVarExp(true); // no more vars after ":" (in foreach only?)
                            break;

                        case EQ_EXP: // in expression after "type var = "
                            // do nothing - leave the EQ_EXP state
                            break;

                        default:
                            reset();
                            break;
                    }
                } // else -> in parens -> do nothing
                break;

                
            default:
                
        }
        
        return true;
    }
    
    public int eot(int offset) {
        return 0;
    }
    
    public void nextBuffer(char[] buffer, int offset, int len,
    int startPos, int preScan, boolean lastBuffer) {
        this.buffer = buffer;
        bufferStartPos = startPos - offset;
    }
    

    private static class JavaVar implements JavaSyntaxSupport.JavaVariable {
        
        private JCExpression typeExp;
        
        private JCExpression varExp;
        
        JavaVar(JCExpression typeExp, JCExpression varExp) {
            this.typeExp = typeExp;
            this.varExp = varExp;
        }

        public JCExpression getTypeExpression() {
            return typeExp;
        }
        
        public JCExpression getVariableExpression() {
            return varExp;
        }

        public String toString() {
            return "TYPE:\n" + typeExp + "\nVAR:\n" + varExp; // NOI18N
        }

    }

    private static class StackedMap implements Map {

        private Stack stack;

        private StackedMap() {
            stack = new Stack();
        }

        public int size() {
            int size = 0;
            for (Iterator it = stack.iterator(); it.hasNext();) {
                size += ((Map)it.next()).size();
            }
            return size;
        }

        public boolean isEmpty() {
            for (Iterator it = stack.iterator(); it.hasNext();) {
                if (!((Map)it.next()).isEmpty())
                    return false;
            }
            return true;
        }

        public boolean containsKey(Object key) {
            for (Iterator it = stack.iterator(); it.hasNext();) {
                if (((Map)it.next()).containsKey(key))
                    return true;
            }
            return false;
        }

        public boolean containsValue(Object value) {
            for (Iterator it = stack.iterator(); it.hasNext();) {
                if (((Map)it.next()).containsValue(value))
                    return true;
            }
            return false;
        }

        public Object get(Object key) {
            for (Iterator it = stack.iterator(); it.hasNext();) {
                Object o = ((Map)it.next()).get(key);
                if (o != null)
                    return o;
            }
            return null;
        }

        public Object put(Object key, Object value) {
            if (stack.isEmpty())
                pushNewScope();
            return ((Map)stack.peek()).put(key, value);
        }

        public Object remove(Object key) {
            for (Iterator it = stack.iterator(); it.hasNext();) {
                Object o = ((Map)it.next()).remove(key);
                if (o != null)
                    return o;
            }
            return null;
        }

        public void putAll(Map t) {
            if (stack.isEmpty())
                pushNewScope();
            ((Map)stack.peek()).putAll(t);
        }

        public void clear() {
            for (Iterator it = stack.iterator(); it.hasNext();) {
                ((Map)it.next()).clear();
            }
        }

        public Set keySet() {
            Set set = new TreeSet();
            for (Iterator it = stack.iterator(); it.hasNext();) {
                set.addAll(((Map)it.next()).keySet());
            }
            return set;
        }

        public Collection values() {
            Collection col = new ArrayList();
            for (Iterator it = stack.iterator(); it.hasNext();) {
                col.addAll(((Map)it.next()).values());
            }
            return col;
        }

        public Set entrySet() {
            Set set = new HashSet();
            for (Iterator it = stack.iterator(); it.hasNext();) {
                set.addAll(((Map)it.next()).entrySet());
            }
            return set;
        }

        public void pushNewScope() {
            stack.push(new HashMap());
        }

        public void removeScope() {
            if (!stack.isEmpty())
                stack.pop();
        }
    }
}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.