0001: /*
0002: * Sun Public License Notice
0003: *
0004: * The contents of this file are subject to the Sun Public License
0005: * Version 1.0 (the "License"). You may not use this file except in
0006: * compliance with the License. A copy of the License is available at
0007: * http://www.sun.com/
0008: *
0009: * The Original Code is NetBeans. The Initial Developer of the Original
0010: * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
0011: * Microsystems, Inc. All Rights Reserved.
0012: */
0013:
0014: package org.netbeans.editor.ext.java;
0015:
0016: import java.util.ArrayList;
0017: import java.util.List;
0018:
0019: import org.netbeans.editor.TokenContextPath;
0020: import org.netbeans.editor.TokenID;
0021: import org.netbeans.editor.TokenProcessor;
0022:
0023: /**
0024: * Token processor that parses the text and produces jc expressions.
0025: *
0026: * @author Miloslav Metelka
0027: * @version 1.00
0028: */
0029:
0030: class JCTokenProcessor implements TokenProcessor {
0031:
0032: private static final int CONSTANT = JCExpression.CONSTANT;
0033: private static final int VARIABLE = JCExpression.VARIABLE;
0034: private static final int OPERATOR = JCExpression.OPERATOR;
0035: private static final int UNARY_OPERATOR = JCExpression.UNARY_OPERATOR;
0036: private static final int DOT = JCExpression.DOT;
0037: private static final int DOT_OPEN = JCExpression.DOT_OPEN;
0038: private static final int ARRAY_OPEN = JCExpression.ARRAY_OPEN;
0039: private static final int ARRAY = JCExpression.ARRAY;
0040: private static final int PARENTHESIS_OPEN = JCExpression.PARENTHESIS_OPEN;
0041: private static final int PARENTHESIS = JCExpression.PARENTHESIS;
0042: private static final int METHOD_OPEN = JCExpression.METHOD_OPEN;
0043: private static final int METHOD = JCExpression.METHOD;
0044: private static final int CONSTRUCTOR = JCExpression.CONSTRUCTOR;
0045: private static final int CONVERSION = JCExpression.CONVERSION;
0046: private static final int TYPE = JCExpression.TYPE;
0047: private static final int NEW = JCExpression.NEW;
0048: private static final int INSTANCEOF = JCExpression.INSTANCEOF;
0049:
0050: private static final int NO_EXP = -1;
0051:
0052: /** Buffer that is scanned */
0053: private char[] buffer;
0054:
0055: /** Start position of the buffer in the document */
0056: private int bufferStartPos;
0057:
0058: /**
0059: * Delta of the token processor buffer offsets against the offsets given in
0060: * the source buffer.
0061: */
0062: private int bufferOffsetDelta;
0063:
0064: /** The scanning was stopped by request by the token processor */
0065: private boolean stopped;
0066:
0067: /** Stack of the expressions. */
0068: private ArrayList expStack = new ArrayList();
0069:
0070: /** TokenID of the last found token except Syntax.EOT and Syntax.EOL */
0071: private TokenID lastValidTokenID;
0072:
0073: /** Text of the last found token except Syntax.EOT and Syntax.EOL */
0074: private String lastValidTokenText;
0075:
0076: // helper variables
0077: private TokenID curTokenID;
0078: private int curTokenPosition;
0079: private String curTokenText;
0080:
0081: JCTokenProcessor() {
0082: }
0083:
0084: /** Get the expression stack from the bottom to top */
0085: final List getStack() {
0086: return expStack;
0087: }
0088:
0089: /**
0090: * Get the last token that was processed that wasn't either Syntax.EOT or
0091: * Syntax.EOL.
0092: */
0093: final TokenID getLastValidTokenID() {
0094: return lastValidTokenID;
0095: }
0096:
0097: final String getLastValidTokenText() {
0098: return lastValidTokenText;
0099: }
0100:
0101: /** Was the scanning stopped by request by the token processor */
0102: final boolean isStopped() {
0103: return stopped;
0104: }
0105:
0106: final JCExpression getResultExp() {
0107: return peekExp();
0108: }
0109:
0110: private void clearStack() {
0111: expStack.clear();
0112: }
0113:
0114: /** Push exp to top of stack */
0115: private void pushExp(JCExpression exp) {
0116: expStack.add(exp);
0117: }
0118:
0119: /** Pop exp from top of stack */
0120: private JCExpression popExp() {
0121: int cnt = expStack.size();
0122: return (cnt > 0) ? (JCExpression) expStack.remove(cnt - 1)
0123: : null;
0124: }
0125:
0126: /** Look at the exp at top of stack */
0127: private JCExpression peekExp() {
0128: int cnt = expStack.size();
0129: return (cnt > 0) ? (JCExpression) expStack.get(cnt - 1) : null;
0130: }
0131:
0132: /** Look at the second exp on stack */
0133: private JCExpression peekExp2() {
0134: int cnt = expStack.size();
0135: return (cnt > 1) ? (JCExpression) expStack.get(cnt - 2) : null;
0136: }
0137:
0138: /** Look at the third exp on stack */
0139: private JCExpression peekExp(int ind) {
0140: int cnt = expStack.size();
0141: return (cnt >= ind) ? (JCExpression) expStack.get(cnt - ind)
0142: : null;
0143: }
0144:
0145: private JCExpression createTokenExp(int id) {
0146: JCExpression exp = new JCExpression(id);
0147: addTokenTo(exp);
0148: return exp;
0149: }
0150:
0151: /** Add the token to a given expression */
0152: private void addTokenTo(JCExpression exp) {
0153: exp.addToken(curTokenID, curTokenPosition, curTokenText);
0154: }
0155:
0156: private int getValidExpID(JCExpression exp) {
0157: return (exp != null) ? exp.getExpID() : NO_EXP;
0158: }
0159:
0160: /**
0161: * Check whether there can be any joining performed for current expressions
0162: * on the stack.
0163: *
0164: * @param tokenID
0165: * tokenID of the current token
0166: * @return true to continue, false if errorneous construction found
0167: */
0168: private boolean checkJoin(TokenID tokenID) {
0169: boolean ret = true;
0170:
0171: boolean cont = true;
0172: while (cont) {
0173: cont = false;
0174: JCExpression top = peekExp();
0175: JCExpression top2 = peekExp2();
0176: int top2ID = getValidExpID(top2);
0177:
0178: switch (getValidExpID(top)) {
0179: case CONSTANT:
0180: case VARIABLE:
0181: case METHOD:
0182: case CONSTRUCTOR:
0183: case ARRAY:
0184: case DOT:
0185: case PARENTHESIS:
0186: case OPERATOR: // operator on top of stack
0187: switch (top2ID) {
0188: case UNARY_OPERATOR:
0189: switch (tokenID.getNumericID()) {
0190: case JavaTokenContext.DOT_ID:
0191: case JavaTokenContext.LPAREN_ID:
0192: case JavaTokenContext.LBRACKET_ID:
0193: case JavaTokenContext.PLUS_PLUS_ID:
0194: case JavaTokenContext.MINUS_MINUS_ID:
0195: break;
0196:
0197: default: // Join
0198: if (top2.getParameterCount() == 0) {
0199: popExp(); // pop top
0200: top2.addParameter(top);
0201: }
0202: break;
0203: }
0204: break;
0205:
0206: case DOT_OPEN:
0207: if (tokenID.getCategory() == JavaTokenContext.OPERATORS) {
0208: switch (tokenID.getNumericID()) {
0209: case JavaTokenContext.LPAREN_ID:
0210: break;
0211: default:
0212: popExp();
0213: top2.addParameter(top);
0214: top2.setExpID(DOT);
0215: }
0216: }
0217: break;
0218:
0219: case CONVERSION:
0220: if (tokenID.getCategory() == JavaTokenContext.OPERATORS) {
0221: switch (tokenID.getNumericID()) {
0222: case JavaTokenContext.RPAREN_ID:
0223: case JavaTokenContext.COMMA_ID:
0224: JCExpression top3 = peekExp(3);
0225: if (top3 != null) {
0226: switch (top3.getExpID()) {
0227: case JCExpression.PARENTHESIS_OPEN:
0228: case JCExpression.METHOD_OPEN:
0229: popExp(); // pop top
0230: top2.addParameter(top); // add last to
0231: // conversion
0232: break;
0233: }
0234: }
0235: break;
0236: }
0237: }
0238: break;
0239:
0240: }
0241: break;
0242: }
0243: }
0244:
0245: int leftOpID = JCExpression.getOperatorID(tokenID);
0246:
0247: if (leftOpID >= 0) {
0248: switch (JCExpression.getOperatorPrecedence(leftOpID)) {
0249: case 0: // stop ID - try to join the exps on stack
0250: JCExpression lastVar = null;
0251: JCExpression rightOp = peekExp();
0252: int rightOpID = -1;
0253: rightOpID = JCExpression.getOperatorID(rightOp);
0254: switch (JCExpression.getOperatorPrecedence(rightOpID)) {
0255: case 0: // stop - nothing to join
0256: rightOp = null;
0257: break;
0258:
0259: case 1: // single item - move to next and add this one
0260: lastVar = rightOp;
0261: rightOp = peekExp2();
0262: rightOpID = JCExpression.getOperatorID(rightOp);
0263: switch (JCExpression
0264: .getOperatorPrecedence(rightOpID)) {
0265: case 0: // stop - only one item on the stack
0266: rightOp = null;
0267: break;
0268:
0269: case 1: // two items without operator - error
0270: ret = false;
0271: rightOp = null;
0272: break;
0273:
0274: default:
0275: popExp(); // pop item
0276: rightOp.addParameter(lastVar); // add item as parameter
0277: lastVar = null;
0278: }
0279: break;
0280: }
0281:
0282: if (rightOp != null) {
0283: popExp(); // pop rightOp
0284: cont = true;
0285: ArrayList opStack = new ArrayList(); // operator stack
0286: JCExpression leftOp = null;
0287: do {
0288: if (leftOp == null) {
0289: leftOp = popExp();
0290: if (leftOp == null) {
0291: break;
0292: }
0293: leftOpID = JCExpression
0294: .getOperatorID(leftOp);
0295: }
0296: switch (JCExpression
0297: .getOperatorPrecedence(leftOpID)) {
0298: case 0: // stop here
0299: pushExp(leftOp); // push last exp back to stack
0300: cont = false;
0301: break;
0302:
0303: case 1: // item found
0304: lastVar = leftOp;
0305: leftOp = null; // ask for next pop
0306: break;
0307:
0308: default: // operator found
0309: int leftOpPrec = JCExpression
0310: .getOperatorPrecedence(leftOpID);
0311: int rightOpPrec = JCExpression
0312: .getOperatorPrecedence(rightOpID);
0313: boolean rightPrec;
0314: if (leftOpPrec > rightOpPrec) { // left has greater
0315: // priority
0316: rightPrec = false;
0317: } else if (leftOpPrec < rightOpPrec) { // right has
0318: // greater
0319: // priority
0320: rightPrec = true;
0321: } else { // equal priorities
0322: rightPrec = JCExpression
0323: .isOperatorRightAssociative(rightOpID);
0324: }
0325:
0326: if (rightPrec) { // right operator has precedence
0327: if (lastVar != null) {
0328: rightOp.addParameter(lastVar);
0329: }
0330: if (opStack.size() > 0) { // at least one
0331: // right stacked op
0332: lastVar = rightOp; // rightOp becomes item
0333: rightOp = (JCExpression) opStack
0334: .remove(opStack.size() - 1); // get
0335: // stacked
0336: // op
0337: rightOpID = rightOp
0338: .getOperatorID(rightOp);
0339: } else { // shift the leftOp to rightOp
0340: leftOp.addParameter(rightOp);
0341: lastVar = null;
0342: rightOp = leftOp;
0343: rightOpID = leftOpID;
0344: leftOp = null; // ask for next poping
0345: }
0346: } else { // left operator has precedence
0347: if (lastVar != null) {
0348: leftOp.addParameter(lastVar);
0349: lastVar = null;
0350: }
0351: opStack.add(rightOp); // push right operator
0352: // to stack
0353: // rightOp.addParameter(leftOp);
0354: rightOp = leftOp; // shift left op to right op
0355: rightOpID = leftOpID;
0356: leftOp = null;
0357: }
0358: }
0359: } while (cont);
0360:
0361: // add possible valid last item
0362: if (lastVar != null) {
0363: rightOp.addParameter(lastVar);
0364: }
0365:
0366: // pop the whole stack adding the current right op to the
0367: // stack exp
0368: for (int i = opStack.size() - 1; i >= 0; i--) {
0369: JCExpression op = (JCExpression) opStack.get(i);
0370: op.addParameter(rightOp);
0371: rightOp = op;
0372: }
0373:
0374: rightOp.swapOperatorParms();
0375: pushExp(rightOp); // push the top operator
0376: }
0377: break;
0378: }
0379: }
0380:
0381: return ret;
0382: }
0383:
0384: public boolean token(TokenID tokenID,
0385: TokenContextPath tokenContextPath, int tokenOffset,
0386: int tokenLen) {
0387:
0388: tokenOffset += bufferOffsetDelta;
0389: // assign helper variables
0390: if (tokenID != null) {
0391: lastValidTokenID = tokenID;
0392: }
0393:
0394: curTokenID = tokenID;
0395: curTokenPosition = bufferStartPos + tokenOffset;
0396: curTokenText = new String(buffer, tokenOffset, tokenLen);
0397: boolean err = false; // whether the parser cannot understand given
0398: // tokens
0399:
0400: checkJoin(tokenID);
0401:
0402: JCExpression top = peekExp(); // exp at top of stack
0403: int topID = getValidExpID(top); // id of the exp at top of stack
0404:
0405: JCExpression constExp = null; // possibly assign constant into this
0406: // exp
0407: JCType kwdType = null; // keyword constant type (used in conversions)
0408:
0409: if (tokenID == null) { // invalid token-id
0410: err = true;
0411:
0412: } else { // valid token-id
0413: switch (tokenID.getNumericID()) { // test the token ID
0414: case JavaTokenContext.BOOLEAN_ID:
0415: kwdType = JavaCompletion.BOOLEAN_TYPE;
0416: break;
0417: case JavaTokenContext.BYTE_ID:
0418: kwdType = JavaCompletion.BYTE_TYPE;
0419: break;
0420: case JavaTokenContext.CHAR_ID:
0421: kwdType = JavaCompletion.CHAR_TYPE;
0422: break;
0423: case JavaTokenContext.DOUBLE_ID:
0424: kwdType = JavaCompletion.DOUBLE_TYPE;
0425: break;
0426: case JavaTokenContext.FLOAT_ID:
0427: kwdType = JavaCompletion.FLOAT_TYPE;
0428: break;
0429: case JavaTokenContext.INT_ID:
0430: kwdType = JavaCompletion.INT_TYPE;
0431: break;
0432: case JavaTokenContext.LONG_ID:
0433: kwdType = JavaCompletion.LONG_TYPE;
0434: break;
0435: case JavaTokenContext.SHORT_ID:
0436: kwdType = JavaCompletion.SHORT_TYPE;
0437: break;
0438:
0439: case JavaTokenContext.TRUE_ID:
0440: case JavaTokenContext.FALSE_ID:
0441: constExp = createTokenExp(CONSTANT);
0442: constExp.setType(JavaCompletion.BOOLEAN_TYPE);
0443: break;
0444:
0445: case JavaTokenContext.NULL_ID:
0446: constExp = createTokenExp(CONSTANT);
0447: constExp.setType(JavaCompletion.NULL_TYPE);
0448: break;
0449:
0450: case JavaTokenContext.CLASS_ID:
0451: if (topID == DOT_OPEN) {
0452: pushExp(createTokenExp(VARIABLE));
0453: } else {
0454: err = true;
0455: }
0456: break;
0457:
0458: case JavaTokenContext.NEW_ID:
0459: switch (topID) {
0460: case VARIABLE:
0461: case NEW:
0462: err = true;
0463: break;
0464:
0465: case DOT_OPEN:
0466: pushExp(createTokenExp(VARIABLE));
0467: break;
0468:
0469: default:
0470: pushExp(createTokenExp(NEW));
0471: break;
0472: }
0473: break;
0474:
0475: case JavaTokenContext.SUPER_ID:
0476: case JavaTokenContext.THIS_ID:
0477: pushExp(createTokenExp(VARIABLE));
0478: break;
0479:
0480: case JavaTokenContext.INSTANCEOF_ID:
0481: switch (topID) {
0482: case CONSTANT:
0483: case VARIABLE:
0484: case METHOD:
0485: case CONSTRUCTOR:
0486: case ARRAY:
0487: case DOT:
0488: case PARENTHESIS:
0489: pushExp(createTokenExp(INSTANCEOF));
0490: break;
0491: default:
0492: err = true;
0493: break;
0494: }
0495: break;
0496:
0497: case JavaTokenContext.VOID_ID:
0498: case JavaTokenContext.ABSTRACT_ID:
0499: case JavaTokenContext.BREAK_ID:
0500: case JavaTokenContext.CASE_ID:
0501: case JavaTokenContext.CATCH_ID:
0502: case JavaTokenContext.CONST_ID:
0503: case JavaTokenContext.CONTINUE_ID:
0504: case JavaTokenContext.DEFAULT_ID:
0505: case JavaTokenContext.DO_ID:
0506: case JavaTokenContext.ELSE_ID:
0507: case JavaTokenContext.EXTENDS_ID:
0508: case JavaTokenContext.FINAL_ID:
0509: case JavaTokenContext.FINALLY_ID:
0510: case JavaTokenContext.FOR_ID:
0511: case JavaTokenContext.GOTO_ID:
0512: case JavaTokenContext.IF_ID:
0513: case JavaTokenContext.IMPLEMENTS_ID:
0514: case JavaTokenContext.IMPORT_ID:
0515: case JavaTokenContext.INTERFACE_ID:
0516: case JavaTokenContext.NATIVE_ID:
0517: case JavaTokenContext.PACKAGE_ID:
0518: case JavaTokenContext.PRIVATE_ID:
0519: case JavaTokenContext.PROTECTED_ID:
0520: case JavaTokenContext.PUBLIC_ID:
0521: case JavaTokenContext.RETURN_ID:
0522: case JavaTokenContext.STATIC_ID:
0523: case JavaTokenContext.SWITCH_ID:
0524: case JavaTokenContext.SYNCHRONIZED_ID:
0525: case JavaTokenContext.THROW_ID:
0526: case JavaTokenContext.THROWS_ID:
0527: case JavaTokenContext.TRANSIENT_ID:
0528: case JavaTokenContext.TRY_ID:
0529: case JavaTokenContext.VOLATILE_ID:
0530: case JavaTokenContext.WHILE_ID:
0531: err = true;
0532: break;
0533:
0534: case JavaTokenContext.IDENTIFIER_ID: // identifier found e.g. 'a'
0535: {
0536: switch (topID) {
0537: case OPERATOR:
0538: case DOT_OPEN:
0539: case ARRAY_OPEN:
0540: case PARENTHESIS_OPEN:
0541: case METHOD_OPEN:
0542: case NEW:
0543: case CONVERSION:
0544: case UNARY_OPERATOR:
0545: case INSTANCEOF:
0546: case NO_EXP:
0547: pushExp(createTokenExp(VARIABLE));
0548: break;
0549:
0550: default:
0551: err = true;
0552: break;
0553: }
0554: }
0555: break;
0556:
0557: case JavaTokenContext.EQ_ID: // Assignment operators
0558: case JavaTokenContext.PLUS_EQ_ID:
0559: case JavaTokenContext.MINUS_EQ_ID:
0560: case JavaTokenContext.MUL_EQ_ID:
0561: case JavaTokenContext.DIV_EQ_ID:
0562: case JavaTokenContext.AND_EQ_ID:
0563: case JavaTokenContext.OR_EQ_ID:
0564: case JavaTokenContext.XOR_EQ_ID:
0565: case JavaTokenContext.MOD_EQ_ID:
0566: case JavaTokenContext.LSHIFT_EQ_ID:
0567: case JavaTokenContext.RSSHIFT_EQ_ID:
0568: case JavaTokenContext.RUSHIFT_EQ_ID:
0569:
0570: case JavaTokenContext.LT_ID: // Binary, result is boolean
0571: case JavaTokenContext.GT_ID:
0572: case JavaTokenContext.LT_EQ_ID:
0573: case JavaTokenContext.GT_EQ_ID:
0574: case JavaTokenContext.EQ_EQ_ID:
0575: case JavaTokenContext.NOT_EQ_ID:
0576:
0577: case JavaTokenContext.AND_AND_ID: // Binary, result is boolean
0578: case JavaTokenContext.OR_OR_ID:
0579:
0580: case JavaTokenContext.LSHIFT_ID: // Always binary
0581: case JavaTokenContext.RSSHIFT_ID:
0582: case JavaTokenContext.RUSHIFT_ID:
0583: case JavaTokenContext.MUL_ID:
0584: case JavaTokenContext.DIV_ID:
0585: case JavaTokenContext.AND_ID:
0586: case JavaTokenContext.OR_ID:
0587: case JavaTokenContext.XOR_ID:
0588: case JavaTokenContext.MOD_ID:
0589:
0590: case JavaTokenContext.QUESTION_ID:
0591: case JavaTokenContext.COLON_ID:
0592:
0593: // Operator handling
0594: switch (topID) {
0595: case CONSTANT:
0596: case VARIABLE:
0597: case METHOD:
0598: case CONSTRUCTOR:
0599: case ARRAY:
0600: case DOT:
0601: case PARENTHESIS:
0602: case OPERATOR:
0603: case UNARY_OPERATOR:
0604: pushExp(createTokenExp(OPERATOR));
0605: break;
0606:
0607: default:
0608: err = true;
0609: break;
0610: }
0611: break;
0612:
0613: case JavaTokenContext.PLUS_PLUS_ID: // Prefix or postfix
0614: case JavaTokenContext.MINUS_MINUS_ID:
0615: switch (topID) {
0616: case METHOD_OPEN:
0617: case ARRAY_OPEN:
0618: case PARENTHESIS_OPEN:
0619: case OPERATOR:
0620: case UNARY_OPERATOR:
0621: case NO_EXP:
0622: // Prefix operator
0623: JCExpression opExp = createTokenExp(UNARY_OPERATOR);
0624: pushExp(opExp); // add operator as new exp
0625: break;
0626:
0627: case VARIABLE: // is it only one permitted?
0628: // Postfix operator
0629: opExp = createTokenExp(UNARY_OPERATOR);
0630: popExp(); // pop top
0631: opExp.addParameter(top);
0632: pushExp(opExp);
0633: break;
0634:
0635: default:
0636: err = true;
0637: break;
0638: }
0639: break;
0640:
0641: case JavaTokenContext.PLUS_ID: // Can be unary or binary
0642: case JavaTokenContext.MINUS_ID:
0643: switch (topID) {
0644: case CONSTANT:
0645: case VARIABLE:
0646: case METHOD:
0647: case CONSTRUCTOR:
0648: case ARRAY:
0649: case DOT:
0650: case PARENTHESIS:
0651: case UNARY_OPERATOR:
0652: JCExpression opExp = createTokenExp(OPERATOR);
0653: pushExp(opExp);
0654: break;
0655:
0656: case METHOD_OPEN:
0657: case ARRAY_OPEN:
0658: case PARENTHESIS_OPEN:
0659: case OPERATOR:
0660: case NO_EXP:
0661: // Unary operator
0662: opExp = createTokenExp(UNARY_OPERATOR);
0663: pushExp(opExp); // add operator as new exp
0664: break;
0665:
0666: default:
0667: err = true;
0668: break;
0669: }
0670: break;
0671:
0672: case JavaTokenContext.NEG_ID: // Always unary
0673: case JavaTokenContext.NOT_ID:
0674: switch (topID) {
0675: case METHOD_OPEN:
0676: case ARRAY_OPEN:
0677: case PARENTHESIS_OPEN:
0678: case OPERATOR:
0679: case UNARY_OPERATOR:
0680: case NO_EXP:
0681: // Unary operator
0682: JCExpression opExp = createTokenExp(UNARY_OPERATOR);
0683: pushExp(opExp); // add operator as new exp
0684: break;
0685:
0686: default:
0687: err = true;
0688: break;
0689: }
0690:
0691: case JavaTokenContext.DOT_ID: // '.' found
0692: switch (topID) {
0693: case CONSTANT:
0694: case VARIABLE:
0695: case ARRAY:
0696: case METHOD:
0697: case CONSTRUCTOR:
0698: case PARENTHESIS:
0699: popExp();
0700: JCExpression opExp = createTokenExp(DOT_OPEN);
0701: opExp.addParameter(top);
0702: pushExp(opExp);
0703: break;
0704:
0705: case DOT:
0706: addTokenTo(top);
0707: top.setExpID(DOT_OPEN);
0708: break;
0709:
0710: default:
0711: err = true;
0712: break;
0713: }
0714: break;
0715:
0716: case JavaTokenContext.COMMA_ID: // ',' found
0717: switch (topID) {
0718: case ARRAY:
0719: case DOT:
0720: case TYPE:
0721: case CONSTANT:
0722: case VARIABLE:
0723: case CONSTRUCTOR:
0724: case CONVERSION:
0725: case PARENTHESIS:
0726: case OPERATOR:
0727: case UNARY_OPERATOR:
0728: case INSTANCEOF:
0729: JCExpression top2 = peekExp2();
0730: switch (getValidExpID(top2)) {
0731: case METHOD_OPEN:
0732: popExp();
0733: top2.addParameter(top);
0734: top = top2;
0735: break;
0736: default:
0737: err = true;
0738: break;
0739: }
0740: break;
0741:
0742: case METHOD_OPEN:
0743: addTokenTo(top);
0744: break;
0745:
0746: default:
0747: err = true;
0748: break;
0749:
0750: }
0751: break;
0752:
0753: case JavaTokenContext.SEMICOLON_ID:
0754: err = true;
0755: break;
0756:
0757: case JavaTokenContext.LPAREN_ID:
0758: switch (topID) {
0759: case VARIABLE:
0760: top.setExpID(METHOD_OPEN);
0761: addTokenTo(top);
0762: break;
0763:
0764: case ARRAY: // a[0](
0765: popExp();
0766: JCExpression mtdExp = createTokenExp(METHOD);
0767: mtdExp.addParameter(top);
0768: pushExp(mtdExp);
0769: break;
0770:
0771: case ARRAY_OPEN: // a[(
0772: case PARENTHESIS_OPEN: // ((
0773: case METHOD_OPEN: // a((
0774: case NO_EXP:
0775: case OPERATOR: // 3+(
0776: case CONVERSION: // (int)(
0777: pushExp(createTokenExp(PARENTHESIS_OPEN));
0778: break;
0779:
0780: default:
0781: err = true;
0782: break;
0783: }
0784: break;
0785:
0786: case JavaTokenContext.RPAREN_ID:
0787: boolean mtd = false;
0788: switch (topID) {
0789: case CONSTANT:
0790: case VARIABLE:
0791: case ARRAY:
0792: case DOT:
0793: case TYPE:
0794: case CONSTRUCTOR:
0795: case CONVERSION:
0796: case PARENTHESIS:
0797: case OPERATOR:
0798: case UNARY_OPERATOR:
0799: case INSTANCEOF:
0800: JCExpression top2 = peekExp2();
0801: switch (getValidExpID(top2)) {
0802: case PARENTHESIS_OPEN:
0803: popExp();
0804: top2.addParameter(top);
0805: top2
0806: .setExpID(JCExpression.isValidType(top) ? CONVERSION
0807: : PARENTHESIS);
0808: addTokenTo(top2);
0809: break;
0810:
0811: case METHOD_OPEN:
0812: popExp();
0813: top2.addParameter(top);
0814: top = top2;
0815: mtd = true;
0816: break;
0817: case CONVERSION:
0818: popExp();
0819: top2.addParameter(top);
0820: top = top2;
0821: top2 = peekExp2();
0822: if (getValidExpID(top2) == PARENTHESIS_OPEN) {
0823: popExp();
0824: top2.addParameter(top);
0825: top2.setExpID(PARENTHESIS);
0826: top = top2;
0827: }
0828:
0829: break;
0830:
0831: default:
0832: err = true;
0833: break;
0834: }
0835: break;
0836:
0837: case METHOD_OPEN:
0838: mtd = true;
0839: break;
0840:
0841: // case PARENTHESIS_OPEN: // empty parenthesis
0842: default:
0843: err = true;
0844: break;
0845: }
0846:
0847: if (mtd) {
0848: addTokenTo(top);
0849: top.setExpID(METHOD);
0850: JCExpression top2 = peekExp2();
0851: switch (getValidExpID(top2)) {
0852: case DOT_OPEN:
0853: JCExpression top3 = peekExp(3);
0854: if (getValidExpID(top3) == NEW) {
0855: popExp(); // pop top
0856: top2.addParameter(top); // add METHOD to DOT
0857: top2.setExpID(DOT);
0858: popExp(); // pop top2
0859: top3.setExpID(CONSTRUCTOR);
0860: top3.addParameter(top2); // add DOT to
0861: // CONSTRUCTOR
0862: }
0863: break;
0864:
0865: case NEW:
0866: top2.setExpID(CONSTRUCTOR);
0867: top2.addParameter(top);
0868: popExp(); // pop top
0869: break;
0870: }
0871: }
0872: break;
0873:
0874: case JavaTokenContext.LBRACKET_ID:
0875: switch (topID) {
0876: case VARIABLE:
0877: case METHOD:
0878: case DOT:
0879: case ARRAY:
0880: case TYPE: // ... int[ ...
0881: popExp(); // top popped
0882: JCExpression arrExp = createTokenExp(ARRAY_OPEN);
0883: addTokenTo(arrExp);
0884: arrExp.addParameter(top);
0885: pushExp(arrExp);
0886: break;
0887:
0888: default:
0889: err = true;
0890: break;
0891: }
0892: break;
0893:
0894: case JavaTokenContext.RBRACKET_ID:
0895: switch (topID) {
0896: case VARIABLE:
0897: case METHOD:
0898: case DOT:
0899: case ARRAY:
0900: case PARENTHESIS:
0901: case CONSTANT:
0902: case OPERATOR:
0903: case UNARY_OPERATOR:
0904: case INSTANCEOF:
0905: JCExpression top2 = peekExp2();
0906: switch (getValidExpID(top2)) {
0907: case ARRAY_OPEN:
0908: popExp(); // top popped
0909: top2.addParameter(top);
0910: top2.setExpID(ARRAY);
0911: addTokenTo(top2);
0912: break;
0913:
0914: default:
0915: err = true;
0916: break;
0917: }
0918: break;
0919:
0920: case ARRAY_OPEN:
0921: top.setExpID(ARRAY);
0922: addTokenTo(top);
0923: break;
0924:
0925: default:
0926: err = true;
0927: break;
0928: }
0929: break;
0930:
0931: case JavaTokenContext.LBRACE_ID:
0932: err = true;
0933: break;
0934:
0935: case JavaTokenContext.RBRACE_ID:
0936: err = true;
0937: break;
0938:
0939: case JavaTokenContext.LINE_COMMENT_ID:
0940: // Skip line comment
0941: break;
0942:
0943: case JavaTokenContext.BLOCK_COMMENT_ID:
0944: // Skip block comment
0945: break;
0946:
0947: case JavaTokenContext.CHAR_LITERAL_ID:
0948: constExp = createTokenExp(CONSTANT);
0949: constExp.setType(JavaCompletion.CHAR_TYPE);
0950: break;
0951:
0952: case JavaTokenContext.STRING_LITERAL_ID:
0953: constExp = createTokenExp(CONSTANT);
0954: constExp.setType(JavaCompletion.STRING_TYPE);
0955: break;
0956:
0957: case JavaTokenContext.INT_LITERAL_ID:
0958: case JavaTokenContext.HEX_LITERAL_ID:
0959: case JavaTokenContext.OCTAL_LITERAL_ID:
0960: constExp = createTokenExp(CONSTANT);
0961: constExp.setType(JavaCompletion.INT_TYPE);
0962: break;
0963:
0964: case JavaTokenContext.LONG_LITERAL_ID:
0965: constExp = createTokenExp(CONSTANT);
0966: constExp.setType(JavaCompletion.LONG_TYPE);
0967: break;
0968:
0969: case JavaTokenContext.FLOAT_LITERAL_ID:
0970: constExp = createTokenExp(CONSTANT);
0971: constExp.setType(JavaCompletion.FLOAT_TYPE);
0972: break;
0973:
0974: case JavaTokenContext.DOUBLE_LITERAL_ID:
0975: constExp = createTokenExp(CONSTANT);
0976: constExp.setType(JavaCompletion.DOUBLE_TYPE);
0977: break;
0978:
0979: } // end of testing keyword type
0980: }
0981:
0982: // Check whether a constant or data type keyword was found
0983: if (constExp != null) {
0984: switch (topID) {
0985: case DOT_OPEN:
0986: err = true;
0987: break;
0988:
0989: case ARRAY_OPEN:
0990: case PARENTHESIS_OPEN:
0991: case PARENTHESIS: // can be conversion
0992: case METHOD_OPEN:
0993: case OPERATOR:
0994: case UNARY_OPERATOR:
0995: case CONVERSION:
0996: case NO_EXP:
0997: pushExp(constExp);
0998: break;
0999:
1000: default:
1001: err = true;
1002: break;
1003: }
1004: }
1005:
1006: if (kwdType != null) { // keyword constant (in conversions)
1007: switch (topID) {
1008: case PARENTHESIS_OPEN: // conversion
1009: JCExpression kwdExp = createTokenExp(TYPE);
1010: addTokenTo(kwdExp);
1011: kwdExp.setType(kwdType);
1012: pushExp(kwdExp);
1013: break;
1014:
1015: default: // otherwise not recognized
1016: err = true;
1017: break;
1018: }
1019: }
1020:
1021: if (err) {
1022: clearStack();
1023:
1024: if (tokenID == JavaTokenContext.IDENTIFIER) {
1025: pushExp(createTokenExp(VARIABLE));
1026: }
1027: }
1028:
1029: return !stopped;
1030: }
1031:
1032: public int eot(int offset) {
1033: // Check for joins
1034: boolean reScan = true;
1035: while (reScan) {
1036: reScan = false;
1037: JCExpression top = peekExp();
1038: JCExpression top2 = peekExp2();
1039: int top2ID = getValidExpID(top2);
1040: if (top != null) {
1041: switch (getValidExpID(top)) {
1042: case VARIABLE:
1043: switch (top2ID) {
1044: case DOT_OPEN:
1045: popExp();
1046: top2.addParameter(top);
1047: top2.setExpID(DOT);
1048: reScan = true;
1049: break;
1050: case NEW:
1051: popExp();
1052: top2.addParameter(top);
1053: top2.setExpID(CONSTRUCTOR);
1054: reScan = true;
1055: break;
1056: }
1057: break;
1058:
1059: case METHOD_OPEN:
1060: // let it flow to METHOD
1061: case METHOD:
1062: switch (top2ID) {
1063: case DOT_OPEN:
1064: popExp();
1065: top2.addParameter(top);
1066: top2.setExpID(DOT);
1067: reScan = true;
1068: break;
1069: case NEW:
1070: popExp();
1071: top2.addParameter(top);
1072: top2.setExpID(CONSTRUCTOR);
1073: reScan = true;
1074: break;
1075: }
1076: break;
1077:
1078: case DOT:
1079: case DOT_OPEN:
1080: switch (top2ID) {
1081: case NEW:
1082: popExp();
1083: top2.addParameter(top);
1084: top2.setExpID(CONSTRUCTOR);
1085: reScan = true;
1086: break;
1087: }
1088: }
1089: } else { // nothing on the stack, create empty variable
1090: pushExp(JCExpression.createEmptyVariable(bufferStartPos
1091: + bufferOffsetDelta + offset));
1092: }
1093: }
1094: // System.out.println(this);
1095: return 0;
1096: }
1097:
1098: public void nextBuffer(char[] buffer, int offset, int len,
1099: int startPos, int preScan, boolean lastBuffer) {
1100: this .buffer = new char[len + preScan];
1101: System.arraycopy(buffer, offset - preScan, this .buffer, 0, len
1102: + preScan);
1103: bufferOffsetDelta = preScan - offset;
1104: this .bufferStartPos = startPos - preScan;
1105: }
1106:
1107: public String toString() {
1108: int cnt = expStack.size();
1109: StringBuffer sb = new StringBuffer();
1110: if (stopped) {
1111: sb.append("Parsing STOPPED by request.\n"); // NOI18N
1112: }
1113: sb.append("Stack size is " + cnt + "\n"); // NOI18N
1114: if (cnt > 0) {
1115: sb.append("Stack expressions:\n"); // NOI18N
1116: for (int i = 0; i < cnt; i++) {
1117: JCExpression e = (JCExpression) expStack.get(i);
1118: sb.append("Stack["); // NOI18N
1119: sb.append(i);
1120: sb.append("]: "); // NOI18N
1121: sb.append(e.toString(0));
1122: sb.append('\n');
1123: }
1124: }
1125: return sb.toString();
1126: }
1127:
1128: }
|