View Javadoc

    1   /**
    2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
    3    */
    4   package net.sourceforge.pmd.lang.dfa;
    5
    6   import java.util.ArrayList;
    7   import java.util.List;
    8
    9
    10  /**
    11   * @author raik
    12   *         <p/>
    13   *         Computes the first sequence in a list.
    14   *         <p/>
    15   *         e.g.
    16   *         IF_START			0
    17   *         WHILE_EXPR		1
    18   *         WHILE_END		2
    19   *         IF_END			3
    20   *         <p/>
    21   *         The first sequence is WHILE_EXPR und WHILE_END. It returns always the
    22   *         first inner nested scope.
    23   */
    24  public class SequenceChecker {
    25
    26      /*
    27       * Element of logical structure of brace nodes.
    28       * */
    29      private static class Status {
    30  	public static final int ROOT = -1;
    31
    32  	private List<Status> nextSteps = new ArrayList<Status>();
    33  	private int type;
    34  	private boolean lastStep;
    35
    36  	public Status(int type) {
    37  	    this(type, false);
    38  	}
    39
    40  	public Status(int type, boolean lastStep) {
    41  	    this.type = type;
    42  	    this.lastStep = lastStep;
    43  	}
    44
    45  	public void addStep(Status type) {
    46  	    nextSteps.add(type);
    47  	}
    48
    49  	public Status step(int type) {
    50  	    for (int i = 0; i < this.nextSteps.size(); i++) {
    51  		if (type == nextSteps.get(i).type) {
    52  		    return nextSteps.get(i);
    53  		}
    54  	    }
    55  	    return null;
    56  	}
    57
    58  	public boolean isLastStep() {
    59  	    return this.lastStep;
    60  	}
    61
    62  	public boolean hasMoreSteps() {
    63  	    return this.nextSteps.size() > 1;
    64  	}
    65      }
    66
    67      private static Status root;
    68
    69      static {
    70  	root = new Status(Status.ROOT);
    71  	Status ifNode = new Status(NodeType.IF_EXPR);
    72  	Status ifSt = new Status(NodeType.IF_LAST_STATEMENT);
    73  	Status ifStWithoutElse = new Status(NodeType.IF_LAST_STATEMENT_WITHOUT_ELSE, true);
    74  	Status elseSt = new Status(NodeType.ELSE_LAST_STATEMENT, true);
    75  	Status whileNode = new Status(NodeType.WHILE_EXPR);
    76  	Status whileSt = new Status(NodeType.WHILE_LAST_STATEMENT, true);
    77  	Status switchNode = new Status(NodeType.SWITCH_START);
    78  	Status caseSt = new Status(NodeType.CASE_LAST_STATEMENT);
    79  	Status switchDefault = new Status(NodeType.SWITCH_LAST_DEFAULT_STATEMENT);
    80  	Status switchEnd = new Status(NodeType.SWITCH_END, true);
    81
    82  	Status forInit = new Status(NodeType.FOR_INIT);
    83  	Status forExpr = new Status(NodeType.FOR_EXPR);
    84  	Status forUpdate = new Status(NodeType.FOR_UPDATE);
    85  	Status forSt = new Status(NodeType.FOR_BEFORE_FIRST_STATEMENT);
    86  	Status forEnd = new Status(NodeType.FOR_END, true);
    87
    88  	Status doSt = new Status(NodeType.DO_BEFORE_FIRST_STATEMENT);
    89  	Status doExpr = new Status(NodeType.DO_EXPR, true);
    90
    91  	Status labelNode = new Status(NodeType.LABEL_STATEMENT);
    92  	Status labelEnd = new Status(NodeType.LABEL_LAST_STATEMENT, true);
    93
    94  	root.addStep(ifNode);
    95  	root.addStep(whileNode);
    96  	root.addStep(switchNode);
    97  	root.addStep(forInit);
    98  	root.addStep(forExpr);
    99  	root.addStep(forUpdate);
    100 	root.addStep(forSt);
    101 	root.addStep(doSt);
    102 	root.addStep(labelNode);
    103
    104 	ifNode.addStep(ifSt);
    105 	ifNode.addStep(ifStWithoutElse);
    106 	ifSt.addStep(elseSt);
    107 	ifStWithoutElse.addStep(root);
    108 	elseSt.addStep(root);
    109
    110 	labelNode.addStep(labelEnd);
    111 	labelEnd.addStep(root);
    112
    113 	whileNode.addStep(whileSt);
    114 	whileSt.addStep(root);
    115
    116 	switchNode.addStep(caseSt);
    117 	switchNode.addStep(switchDefault);
    118 	switchNode.addStep(switchEnd);
    119 	caseSt.addStep(caseSt);
    120 	caseSt.addStep(switchDefault);
    121 	caseSt.addStep(switchEnd);
    122 	switchDefault.addStep(switchEnd);
    123 	switchDefault.addStep(caseSt);
    124 	switchEnd.addStep(root);
    125
    126 	forInit.addStep(forExpr);
    127 	forInit.addStep(forUpdate);
    128 	forInit.addStep(forSt);
    129 	forExpr.addStep(forUpdate);
    130 	forExpr.addStep(forSt);
    131 	forUpdate.addStep(forSt);
    132 	forSt.addStep(forEnd);
    133 	forEnd.addStep(root);
    134
    135 	doSt.addStep(doExpr);
    136 	doExpr.addStep(root);
    137     }
    138
    139     private Status aktStatus;
    140     private List<StackObject> bracesList;
    141
    142     private int firstIndex = -1;
    143     private int lastIndex = -1;
    144
    145     /*
    146      * Defines the logical structure.
    147      * */
    148     public SequenceChecker(List<StackObject> bracesList) {
    149 	this.aktStatus = root;
    150 	this.bracesList = bracesList;
    151     }
    152
    153     /**
    154      * Finds the first most inner sequence e.g IFStart & IFEnd. If no sequence
    155      * is found or the list is empty the method returns false.
    156      */
    157     public boolean run() {
    158 	this.aktStatus = root;
    159 	this.firstIndex = 0;
    160 	this.lastIndex = 0;
    161 	boolean lookAhead = false;
    162
    163 	for (int i = 0; i < this.bracesList.size(); i++) {
    164 	    StackObject so = bracesList.get(i);
    165 	    aktStatus = this.aktStatus.step(so.getType());
    166
    167 	    if (aktStatus == null) {
    168 		if (lookAhead) {
    169 		    this.lastIndex = i - 1;
    170 		    return false;
    171 		}
    172 		this.aktStatus = root;
    173 		this.firstIndex = i;
    174 		i--;
    175 		continue;
    176 	    } else {
    177 		if (aktStatus.isLastStep() && !aktStatus.hasMoreSteps()) {
    178 		    this.lastIndex = i;
    179 		    return false;
    180 		} else if (aktStatus.isLastStep() && aktStatus.hasMoreSteps()) {
    181 		    lookAhead = true;
    182 		    this.lastIndex = i;
    183 		}
    184 	    }
    185 	}
    186 	return this.firstIndex == this.lastIndex;
    187     }
    188
    189     public int getFirstIndex() {
    190 	return this.firstIndex;
    191     }
    192
    193     public int getLastIndex() {
    194 	return this.lastIndex;
    195     }
    196
    197 }