Source Code Cross Referenced for SyntaxUtils.java in  » IDE » tIDE » tide » utils » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE » tIDE » tide.utils 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        package tide.utils;
0002:
0003:        import tide.editor.MainEditorFrame;
0004:        import snow.texteditor.*;
0005:        import java.util.regex.*;
0006:        import java.util.*;
0007:        import snow.utils.StringUtils;
0008:
0009:        /** To fetch syntax info directly from source string representation.
0010:         *  Quicker than javaCC, used for edit and completion purposes.
0011:         *  Other advantage: parses locally, also when not globally valid.
0012:         */
0013:        public class SyntaxUtils {
0014:            /** @return 0 if the pos is on the first line.
0015:             *  Just count the return backslash + n, ignore CRs
0016:             */
0017:            public static int countLinesUpToPosition(String txt, int pos) {
0018:                int count = 0;
0019:                for (int i = 0; i < pos; i++) {
0020:                    if (txt.charAt(i) == '\n')
0021:                        count++;
0022:                }
0023:                return count;
0024:            }
0025:
0026:            /** @return true if on the same line, an uneven number of " is present
0027:               TODO: odd slashes \ befor " invalidate them
0028:               TODO: also look for '
0029:             */
0030:            public static boolean isInString(String txt, int posItem) {
0031:                // look backward on the same line
0032:                int pos = posItem - 1;
0033:                int numberOfA = 0; // A="
0034:                while (pos >= 0) {
0035:                    char ci = txt.charAt(pos);
0036:                    if (ci == '"')
0037:                        numberOfA++;
0038:                    if (ci == '\n' || ci == '\r')
0039:                        break;
0040:                    pos--;
0041:                }
0042:
0043:                return (numberOfA & 1) != 0;
0044:            }
0045:
0046:            /** in a comment iff preceded by some // on the same line
0047:             *   // TODO: ignore " that are in literals !
0048:             */
0049:            public static boolean isInComment(String txt, int posItem) {
0050:                // look backward on the same line
0051:                int pos = posItem - 1;
0052:                boolean sameLine = true;
0053:                //boolean foundEndComment = false;
0054:                //boolean foundStartComment = false;
0055:                while (pos >= 0) {
0056:                    char ci = txt.charAt(pos);
0057:                    if (ci == '/') {
0058:                        if (txt.charAt(pos + 1) == '*') {
0059:                            //foundStartComment = true;
0060:                            return true;
0061:                        }
0062:
0063:                        if (pos == 0)
0064:                            return false;
0065:                        if (sameLine && txt.charAt(pos - 1) == '/') {
0066:                            // TODO: ignore if // is in in litterals ! "//"
0067:                            return true;
0068:                        }
0069:
0070:                        if (txt.charAt(pos - 1) == '*') // we have */
0071:                        {
0072:                            //foundEndComment = true;
0073:                            // we're just after an ending multiline comment => sure that we're not in a comment !
0074:                            // even if // preceeds on the same line
0075:                            return false;
0076:                        }
0077:
0078:                    } else if (ci == '\n') {
0079:                        sameLine = false;
0080:                    }
0081:                    pos--;
0082:                }
0083:
0084:                return false;
0085:            }
0086:
0087:            /** Example: snow.utils.gui.FileChooserFilter$SearchHit => snow.utils.gui
0088:             */
0089:            public static String getPackageName(String jn) {
0090:                int posPt = jn.lastIndexOf('.');
0091:                if (posPt < 0)
0092:                    return jn;
0093:                return jn.substring(0, posPt);
0094:            }
0095:
0096:            /** Given an argument string, like "123, var, nd(1), 2",
0097:             * @return the number of the argument (0 for the first). 4 in this case
0098:             */
0099:            public static int getArgumentNumberAtEnd(String as) {
0100:                int parenthesisDepth = 0;
0101:                int argCount = 0;
0102:
0103:                boolean inComment1 = false; // '
0104:                boolean inComment2 = false; // "
0105:
0106:                cl: for (int i = 0; i < as.length(); i++) {
0107:                    char ci = as.charAt(i);
0108:                    if (inComment1) {
0109:                        if (ci == '\'')
0110:                            inComment1 = false;
0111:                        continue cl;
0112:                    }
0113:
0114:                    if (inComment2) {
0115:                        if (ci == '\"')
0116:                            inComment2 = false;
0117:                        continue cl;
0118:                    }
0119:
0120:                    if (ci == '\'') {
0121:                        inComment1 = true;
0122:                        continue cl;
0123:                    }
0124:                    if (ci == '\"') {
0125:                        inComment2 = true;
0126:                        continue cl;
0127:                    }
0128:
0129:                    if (ci == '(' && i > 0)
0130:                        parenthesisDepth++;
0131:                    if (ci == ')')
0132:                        parenthesisDepth--;
0133:
0134:                    if (ci == ',' && parenthesisDepth == 0) {
0135:                        argCount++;
0136:                    }
0137:
0138:                }
0139:                //System.out.println("Args at end of \""+as+"\" is "+argCount);
0140:                return argCount;
0141:            }
0142:
0143:            /** Takes greedilly a full java identifier before the position given.
0144:             *
0145:                Used from document filter when "." is pressed somewhere for completion purposes.
0146:                Quick and not requiring a compilable state...
0147:
0148:                 xxx. yyy.zzz =>  "xxx.yyy.zzz";
0149:                 xxx. yy y.zzz =>  "y.zzz";
0150:
0151:                 xxx.yyy(12.32, z())[8].zzz => xxx.yyy()[].zzz
0152:
0153:               casts are reduced
0154:                 ((Double) xxx).doubleValue()  => {C:Double}.doubleValue()
0155:
0156:               type variable also
0157:                  Vector<Double>  => Vector{TV:Double}
0158:
0159:
0160:                Don't look at Character.isJavaIdentifierStart() limitations.
0161:                Not very exact, somehow tolerant...
0162:
0163:                @return the identifier, without spaces.
0164:
0165:                TODO2: count args at level -1 of parenthesis (number of ",") , allow [ ] in args
0166:                April2007: skip (ignore( the type params as in Vector<Object>() => Vector();
0167:                May2007: improved
0168:                @param prepend "this." in the case of CTRL+space completion
0169:             */
0170:            public static ParsedID getJavaIdentifierBefore(SimpleDocument doc,
0171:                    final int pos, String prepend) {
0172:                StringBuilder completeId = new StringBuilder();
0173:                StringBuilder id = new StringBuilder();
0174:
0175:                boolean isPreviousWhite = false;
0176:                boolean isPreviousNonWhitePoint = false;
0177:                int isInParenthesisDepth = 0;
0178:                int isInBracketDepth = 0;
0179:                int isInTypeParamDepth = 0;
0180:                boolean isInLitteral1 = false;
0181:                boolean isInLitteral2 = false;
0182:
0183:                int lastInsertPos = pos - 1;
0184:
0185:                // reverse parsing from pos-1 (the last char to consider)
0186:                int i = pos - 1;
0187:
0188:                el: for (; i >= 0; i--) {
0189:                    final char ci = doc.getCharAt(i);
0190:                    completeId.insert(0, ci);
0191:                    boolean refuseThisChar = false;
0192:
0193:                    if (ci == '\n') {
0194:                        // special whitespace: te line we are going to analyse from the end may contain a comment that must be skipped
0195:                        // we jump to the previous line
0196:                        String line = DocumentUtils.getTextOfLineAtPosition(
0197:                                doc, i);
0198:                        //System.out.println("Previous Line: "+line);
0199:                        int posComment = line.indexOf("//");
0200:                        if (posComment >= 0) {
0201:                            //System.out.println("Contains a comment => skipping it !");
0202:                            // => continue reading from that pos
0203:                            i = DocumentUtils.getDocPositionFor(doc,
0204:                                    DocumentUtils.getLineNumber(doc, i),
0205:                                    posComment);
0206:                        }
0207:
0208:                        isPreviousWhite = true;
0209:                        continue el; // never added
0210:
0211:                    } else if (Character.isWhitespace(ci)) {
0212:                        if (!isInLitteral1 && !isInLitteral2) // [May2007]
0213:                        {
0214:                            isPreviousWhite = true;
0215:                        }
0216:                        continue el; // never added
0217:                    } else if (ci == '.') {
0218:                        isPreviousWhite = false;
0219:                        if (isPreviousNonWhitePoint) {
0220:                            //System.out.println("stop3, two points found");
0221:                            break el;
0222:                        }
0223:                        isPreviousNonWhitePoint = true;
0224:                    } else if (ci == ',') // [Aug2006] delimiter for args => keep
0225:                    {
0226:                        isPreviousWhite = false;
0227:                        if (isInParenthesisDepth == 0
0228:                                && isInTypeParamDepth == 0) {
0229:                            //System.out.println("stop5");
0230:                            break el;
0231:                        }
0232:                    } else if (ci == '\'') // TODO: better
0233:                    {
0234:                        isPreviousWhite = false;
0235:                        if (isInParenthesisDepth == 0
0236:                                && isInTypeParamDepth == 0)
0237:                            break el; // stop !
0238:
0239:                        isInLitteral2 = !isInLitteral2;
0240:                        refuseThisChar = true;
0241:                    } else if (ci == '"') {
0242:                        isPreviousWhite = false;
0243:                        if (isInParenthesisDepth == 0
0244:                                && isInTypeParamDepth == 0) {
0245:                            break el; // stop !
0246:                        }
0247:
0248:                        isInLitteral1 = !isInLitteral1;
0249:                        refuseThisChar = true;
0250:                    } else if (Character.isJavaIdentifierPart(ci)) {
0251:                        //System.out.println(""+ci);
0252:
0253:                        // only accept spaces around dots and in args
0254:                        if (isInParenthesisDepth == 0
0255:                                && isInTypeParamDepth == 0 && isPreviousWhite
0256:                                && !isPreviousNonWhitePoint) {
0257:
0258:                            //System.out.println("stop2, "+ci);
0259:                            break el;
0260:                        }
0261:
0262:                        isPreviousWhite = false;
0263:                        isPreviousNonWhitePoint = false;
0264:                    } else if (ci == ')') {
0265:                        /*String ids = completeId.substring(1).trim();
0266:                        if(ids.length()>0 && Character.isJavaIdentifierStart(ids.charAt(0)))
0267:                        {
0268:                          //System.out.println("In cast "+ids+", d="+isInParenthesisDepth);
0269:                        }*/
0270:
0271:                        if (isInParenthesisDepth == 0) {
0272:                            id.insert(0, ci); // must be inserted because ignored below
0273:                            lastInsertPos = i;
0274:                            refuseThisChar = true;
0275:                        }
0276:                        isInParenthesisDepth++;
0277:                    } else if (ci == '(') {
0278:                        isPreviousWhite = false; // [May2007]: was missing.
0279:                        isInParenthesisDepth--;
0280:                        if (isInParenthesisDepth < 0) {
0281:                            MainEditorFrame
0282:                                    .debugOut("stop1, beginning ( parenthesis found");
0283:                            break el;
0284:                        }
0285:                    } else if (ci == ']') {
0286:                        isPreviousWhite = false;
0287:                        if (isInParenthesisDepth > 0)
0288:                            continue;
0289:
0290:                        id.insert(0, ci); // must be inserted because ignored below
0291:                        lastInsertPos = i;
0292:                        isInBracketDepth++;
0293:                    } else if (ci == '[') {
0294:                        isPreviousWhite = false;
0295:                        if (isInParenthesisDepth > 0)
0296:                            continue;
0297:
0298:                        isInBracketDepth--;
0299:                        if (isInBracketDepth < 0) {
0300:                            //System.out.println("stop4, beginning [ found");
0301:                            break el;
0302:                        }
0303:                    } else if (ci == '>') {
0304:                        isPreviousWhite = false;
0305:                        isInTypeParamDepth++;
0306:                    } else if (ci == '<') {
0307:                        isPreviousWhite = false;
0308:                        isInTypeParamDepth--;
0309:                        if (isInTypeParamDepth < 0) {
0310:                            //System.out.println("stop5, < found");
0311:                            break el;
0312:                        }
0313:                    } else if (isInBracketDepth > 0 || isInParenthesisDepth > 0
0314:                            || /*isInTypeParamDepth>0 ||*/
0315:                            isInLitteral2 || isInLitteral1) {
0316:                        continue el;
0317:                    } else {
0318:                        //System.out.println("stop6 "+ci);
0319:                        break el;
0320:                    }
0321:
0322:                    if (refuseThisChar) {
0323:                        //System.out.println("   refuse");
0324:                        continue el;
0325:                    }
0326:
0327:                    // ignore bracket contents but let parenthesis !! [April2007], they are removed below
0328:                    if (isInBracketDepth > 0 /*|| isInParenthesisDepth>0*/
0329:                            || isInLitteral2 || isInLitteral1) {
0330:                        continue el;
0331:                    }
0332:
0333:                    // accept it
0334:                    lastInsertPos = i;
0335:                    id.insert(0, ci);
0336:                }
0337:
0338:                // System.out.println("id0='"+id+"'");
0339:
0340:                int startPos = lastInsertPos;
0341:
0342:                // look before
0343:
0344:                StringBuilder before = new StringBuilder();
0345:                al: for (; i >= 0; i--) {
0346:                    char ci = doc.getCharAt(i);
0347:                    if (before.length() == 0) {
0348:                        //first char
0349:                        if (Character.isWhitespace(ci))
0350:                            continue al;
0351:                        if ("{}()[]\"'+-*/%^|&".indexOf(ci) >= 0) {
0352:                            // as first => add
0353:                            before.insert(0, ci);
0354:                            break al;
0355:                        }
0356:                    } else {
0357:                        if (Character.isWhitespace(ci))
0358:                            break al;
0359:                        if (!Character.isLetterOrDigit(ci))
0360:                            break al;
0361:                    }
0362:
0363:                    before.insert(0, ci);
0364:                }
0365:
0366:                StringBuilder after = new StringBuilder();
0367:                afl: for (i = pos; i < doc.getLength(); i++) {
0368:                    char ci = doc.getCharAt(i);
0369:                    if (!Character.isWhitespace(ci)) {
0370:                        after.append(ci);
0371:                        break afl;
0372:                    }
0373:                }
0374:
0375:                // [Feb2007]    if() xxx and for() and other such starts are removed, they are no casts
0376:                /* int parPos = id.indexOf("()");
0377:                 if(parPos>0) //strict
0378:                 {
0379:                    String kw = id.substring(0,parPos).trim();
0380:                    if(SyntaxUtils.isKeyWord( kw ))
0381:                    {
0382:                       System.out.println("removing keyword() at beginning of "+id);
0383:                       //id = id.substring(parPos+2);
0384:                       id.replace(0,parPos+2, "");
0385:
0386:                       startPos += kw.length()+2;   //plus the content of () ;-( ...  //TODO
0387:                    }
0388:                 }
0389:                 else if(parPos==0)
0390:                 {
0391:                    id.replace(0,2,"");
0392:                    startPos += 2; //plus the content of () ;-( ...  //TODO
0393:                 }*/
0394:
0395:                // ignore '.' at beginning
0396:                if (id.length() > 0 && id.charAt(0) == '.') {
0397:                    //ParsedID pid = new ParsedID(id.substring(1), before.toString(), after.toString(), startPos);
0398:                    //return pid;
0399:                    id.replace(0, 1, "");
0400:                    before.append("."); // shift startPos ??
0401:                }
0402:
0403:                // reduce casts ( ((Double)xxx).nono(23,43).doubleValue()  => #Double.nono().doubleValue()
0404:                Map<String, String> castsReplacements = replaceAllCastsWithName(id);
0405:                // remove parenthesis contents (casts are already removed, remains only the args)
0406:                removeAllContents(id, '(', ')');
0407:
0408:                // reduce type variables
0409:                Map<String, String> typeVariablesReplacements = replaceAllTypeVariablesWithName(id);
0410:                removeAllContents(id, '<', '>');
0411:
0412:                /* if(castsReplacements.size()>0)
0413:                    System.out.println("C:"+castsReplacements);
0414:                 if(typeVariablesReplacements.size()>0)
0415:                    System.out.println("TV:"+typeVariablesReplacements);
0416:
0417:                 System.out.println("id="+id);
0418:                 System.out.println("bef="+before);
0419:                 System.out.println("after="+after);
0420:                 */
0421:
0422:                // [May2007]: "if()System.out.println()"
0423:                falseCastMatcher.reset(id);
0424:                if (falseCastMatcher.find()) {
0425:                    int st = falseCastMatcher.start();
0426:                    //System.out.println("########################### False cast found in "+id+", st="+st);
0427:                    //System.out.println("Removing: "+id.substring(0,st+1));
0428:                    before.append(id.substring(0, st + 1));
0429:                    id.delete(0, st + 1);
0430:
0431:                    // shift startPos ??
0432:                }
0433:
0434:                // a new special case...
0435:                String ids = id.toString();
0436:                if (ids.startsWith(">")) {
0437:                    ids = ids.substring(1);
0438:                    before.append(">"); // shift startPos ??
0439:                }
0440:
0441:                if (prepend != null) // [Feb2008]
0442:                {
0443:                    ids = prepend + ids;
0444:                }
0445:
0446:                ParsedID pid = new ParsedID(ids, before.toString(), after
0447:                        .toString(), startPos, castsReplacements,
0448:                        typeVariablesReplacements);
0449:                return pid;
0450:            }
0451:
0452:            /** @return the same passed ref for convenience.
0453:             *  Removes all the content between the balanced open, end items.
0454:             *  Useful for example to remove type params, "<", ">".
0455:             */
0456:            public static StringBuilder removeAllContents(
0457:                    final StringBuilder ids, char open, char end) {
0458:                int posSt = 0;
0459:                while ((posSt = ids.indexOf(String.valueOf(open), posSt)) >= 0) {
0460:                    int posEnd = matchingEndBrace(ids, posSt, open, end);
0461:                    if (posEnd < 0)
0462:                        return ids;
0463:
0464:                    ids.replace(posSt + 1, posEnd, "");
0465:
0466:                    posSt++;
0467:                }
0468:                return ids;
0469:
0470:            }
0471:
0472:            /** Reduce type variables Vector<String>  => Vector#{TV:1}
0473:             *  the map contains the replacements {1,String}.
0474:             */
0475:            public static Map<String, String> replaceAllTypeVariablesWithName(
0476:                    StringBuilder ids) {
0477:                Map<String, String> replacements = new HashMap<String, String>();
0478:                String idt = ids.toString();
0479:                int posSt = -1;
0480:                while ((posSt = ids.indexOf("<", posSt + 1)) >= 0) {
0481:                    int posEnd = matchingEndBrace(ids, posSt, '<', '>');
0482:                    if (posEnd < 0)
0483:                        continue;
0484:
0485:                    int n = replacements.size() + 1;
0486:                    String vn = ids.substring(posSt + 1, posEnd);
0487:                    replacements.put("" + n, vn);
0488:                    ids.replace(posSt, posEnd + 1, "{TV:" + n + "}");
0489:                }
0490:
0491:                return replacements;
0492:            }
0493:
0494:            /** Reduce casts ( ((Double)xxx).nono(23,43).doubleValue()  => #{C:1}.nono().doubleValue()
0495:             *  the map contains the replacements {1,Double}.
0496:             */
0497:            public static Map<String, String> replaceAllCastsWithName(
0498:                    StringBuilder ids) {
0499:                //System.out.println("replaceAllCastsWithName in "+ids);
0500:                Map<String, String> replacements = new HashMap<String, String>();
0501:                String idt = ids.toString();
0502:                // shared matcher !
0503:                castMatcher.reset(idt);
0504:                int posSt = 0;
0505:                while (castMatcher.find(posSt)) {
0506:                    posSt = castMatcher.end(1) + 1; // search next from end
0507:                    //System.out.println("Cast: "+castMatcher.group(1));
0508:                    int beg = castMatcher.start(1);
0509:                    int end = castMatcher.end(1);
0510:
0511:                    // search previous opening  (
0512:                    int begRep = -1;
0513:                    sb: for (int i = beg - 2; i >= 0; i--) // start from one  before "("
0514:                    {
0515:                        if (ids.charAt(i) == '(') {
0516:                            begRep = i;
0517:                            break sb;
0518:                        }
0519:                    }
0520:                    if (begRep < 0)
0521:                        continue; // go to next
0522:                    // search corresponding ending )
0523:                    int endRep = matchingEndBrace(idt, begRep, '(', ')');
0524:                    if (endRep < 0)
0525:                        continue; // go to next
0526:
0527:                    //System.out.println("cast par "+idt.substring(begRep,endRep+1));
0528:                    int n = replacements.size() + 1;
0529:                    replacements.put("" + n, castMatcher.group(1));
0530:                    ids.replace(begRep, endRep + 1, "{C:" + n + "}");
0531:
0532:                    // continue from the end
0533:                    posSt = endRep + 1;
0534:                }
0535:
0536:                return replacements;
0537:            }
0538:
0539:            public static int matchingEndBrace(CharSequence text, int pos,
0540:                    char open, char end) {
0541:                int depth = 1;
0542:                for (int i = pos + 1; i < text.length(); i++) {
0543:                    if (text.charAt(i) == open)
0544:                        depth++;
0545:                    else if (text.charAt(i) == end) {
0546:                        depth--;
0547:                        if (depth == 0)
0548:                            return i;
0549:                    }
0550:                }
0551:                return -1;
0552:
0553:            }
0554:
0555:            // Used to locate casts. Because regex does not perform balancing,
0556:            //  this only locate the cast, the external ( and ) if any must be balanced search.
0557:            //  the string must be without spaces.
0558:            static Matcher castMatcher = Pattern.compile(
0559:                    "\\(([\\w0-9_\\.<>]+?)\\)[\\w_$0-9]").matcher("");
0560:
0561:            // utility to remove special constructs... HAckKKK
0562:            static Matcher falseCastMatcher = Pattern.compile("\\)[^\\.${<]")
0563:                    .matcher(""); // NOT dot
0564:
0565:            /** Not really robust, but is a minimal condition to look before trying to execute some class.
0566:             */
0567:            public static boolean hasStaticMainMethod(String txt) {
0568:                // the declaring class may NOT NECESSARY PUBLIC !
0569:                // args may be String[] or String...
0570:
0571:                Matcher m = publicstaticvoidmain.matcher(txt);
0572:                return m.find();
0573:            }
0574:
0575:            // no need to put ( at end, a void main is a method...
0576:            //  todo: only accept String[] or String... signatures)
0577:            static final Pattern publicstaticvoidmain = Pattern
0578:                    .compile("public\\s+static\\s+void\\s+main");
0579:
0580:            /** Used in javadoc completion.
0581:             *  @return [0]: the return type
0582:             *  @return [1]: the arguments names list  (ONLY MADE)
0583:             *  @return [2]: the throws list
0584:             * this must be called from within a comment
0585:             */
0586:            public static ArrayList<String>[] parseSignatureAfterForJavaDoc(
0587:                    String doc, int pos) {
0588:                @SuppressWarnings("unchecked")
0589:                ArrayList<String>[] ret = new ArrayList[3];
0590:
0591:                // 1) seek comment end
0592:                int posEndComment = -1;
0593:                sl: for (int i = pos; i < doc.length() - 1; i++) {
0594:                    if (doc.charAt(i) == '*' && doc.charAt(i + 1) == '/') // < length-1  ==> can access i+1
0595:                    {
0596:                        posEndComment = i + 1;
0597:                        break sl;
0598:                    }
0599:                }
0600:
0601:                if (posEndComment == -1) {
0602:                    System.out.println("no end comment "
0603:                            + doc.substring(pos, pos + 20));
0604:                    return null;
0605:                }
0606:
0607:                // 2) search open parenthesis, stop if ";" encountered
0608:                //   TODO: scan the return type (and modifiers)
0609:
0610:                int posOpenParenthesis = -1; // (
0611:                sl: for (int i = posEndComment + 1; i < doc.length(); i++) {
0612:                    char ci = doc.charAt(i);
0613:                    if (ci == '(') {
0614:                        posOpenParenthesis = i;
0615:                        break sl;
0616:                    } else if (ci == ';')
0617:                        break;
0618:                }
0619:
0620:                if (posOpenParenthesis == -1) {
0621:                    System.out.println("no open parenthesis"
0622:                            + doc.substring(pos, pos + 20));
0623:                    return null;
0624:                }
0625:
0626:                // 3) scan for arguments
0627:
0628:                // go until "{" or ";"
0629:
0630:                // TODO: ignore comments
0631:                int posEndParenthesis = -1; // )
0632:                ArrayList<String> params = new ArrayList<String>();
0633:                ret[1] = params;
0634:                StringBuilder actualParam = new StringBuilder();
0635:                sl: for (int i = posOpenParenthesis + 1; i < doc.length() - 1; i++) // < length-1  ==> can access i+1
0636:                {
0637:                    char ci = doc.charAt(i);
0638:                    if (ci == '{')
0639:                        break;
0640:                    else if (ci == ';')
0641:                        break;
0642:                    else if (ci == '{') {
0643:                    } else if (ci == ')') {
0644:                        if (actualParam.length() > 0) {
0645:                            params.add(extractNameFromDecl(actualParam
0646:                                    .toString().trim()));
0647:                            actualParam.setLength(0);
0648:                        }
0649:                        posEndParenthesis = i;
0650:                        break;
0651:                    } else if (ci == ',') {
0652:                        if (actualParam.length() > 0) {
0653:                            params.add(extractNameFromDecl(actualParam
0654:                                    .toString().trim()));
0655:                            actualParam.setLength(0);
0656:                        }
0657:                    } else {
0658:                        actualParam.append(ci);
0659:                    }
0660:                }
0661:
0662:                // 4) scan the throws until "{"
0663:
0664:                //System.out.println("params="+params);
0665:                return ret;
0666:            }
0667:
0668:            /**   "int a" => a
0669:             */
0670:            private static String extractNameFromDecl(final String decl) {
0671:                int pos = decl.lastIndexOf(' ');
0672:                if (pos == -1) {
0673:                    MainEditorFrame.debugOut("Cannot extract name from '"
0674:                            + decl + "'");
0675:                    return decl;
0676:                }
0677:                return decl.substring(pos + 1);
0678:            }
0679:
0680:            /** TEST CASE
0681:             */
0682:            private static void test_getJavaIdentifierBefore() {
0683:                test_getJavaIdentifierBefore(
0684:                        "[]de(xxx(23).a$_3[7][3] . yy2y. zzz[](1, \"33[]\", abc(\"12\"), \"1/2\")",
0685:                        "xxx().a$_3[][].yy2y.zzz[]()");
0686:                test_getJavaIdentifierBefore(
0687:                        "((JFrame) aaa).hello(1,2, 3, aa(17, (JInternalFrame) abc))",
0688:                        "{C:1}.hello(1,2,3,aa(17,{C:2}");
0689:                test_getJavaIdentifierBefore(
0690:                        " javax.\n//commentedline xxx.\r\n  swing.JFrame.EXIT_ON_CLOSE",
0691:                        "javax.swing.JFrame.EXIT_ON_CLOSE");
0692:                test_getJavaIdentifierBefore("a(1).b(2).c().d()",
0693:                        "a().b().c().d()");
0694:                test_getJavaIdentifierBefore("new Vector<String", "String");
0695:                test_getJavaIdentifierBefore("new Vector<String>()",
0696:                        "Vector{TV:1}()");
0697:                test_getJavaIdentifierBefore("((Double) xxx).doubleValue()",
0698:                        "{C:1}.doubleValue()");
0699:                test_getJavaIdentifierBefore(
0700:                        "((Double<Int>) xxx).nono(23,43).doubleValue(<23>)<String>",
0701:                        "{C:1}.nono().doubleValue(){TV:1}");
0702:                test_getJavaIdentifierBefore("if(true){ System.out.println()",
0703:                        "System.out.println()");
0704:                test_getJavaIdentifierBefore("if(true) System.out.println()",
0705:                        "System.out.println()");
0706:                test_getJavaIdentifierBefore("System.out.println(\"ohlala\")",
0707:                        "System.out.println()");
0708:                test_getJavaIdentifierBefore("System.out.println(\"   \")",
0709:                        "System.out.println()");
0710:                test_getJavaIdentifierBefore("println(1,2)", "println()");
0711:                test_getJavaIdentifierBefore("println( 1, 2 )", "println()");
0712:                test_getJavaIdentifierBefore(">println( 1, 2 )", "println()");
0713:
0714:            }
0715:
0716:            private static void test_getJavaIdentifierBefore(String id,
0717:                    String res) {
0718:                System.out.println("\ntesting <<" + id + ">>");
0719:                SimpleDocument doc = new SimpleDocument();
0720:                doc.append(id);
0721:
0722:                ParsedID pid = getJavaIdentifierBefore(doc, doc.getLength(),
0723:                        null);
0724:                if (!pid.identifierChain.equals(res)) {
0725:                    System.out.println("##### ERROR: " + pid.identifierChain);
0726:                    throw new RuntimeException();
0727:                    //new Throwable().printStackTrace();
0728:                } else {
0729:                    System.out.println("\t\t ok: " + pid.identifierChain);
0730:                }
0731:            }
0732:
0733:            /**  a.b.d is valid, 12.43 not.
0734:             *  keywords are not allowed, names starting with bad letter also not.
0735:             *  (JFrame) as simplified cast form of ((JFrame) aa) is allowed
0736:             */
0737:            public static boolean isValidIdentifier(String id) {
0738:                if (id.length() == 0)
0739:                    return false;
0740:                // only this, super and class keywords are accepted as parts of expressions   (e.g. void.class is valid !)
0741:                if (id.equals("this") || id.equals("super")
0742:                        || id.equals("class") || id.equals("void"))
0743:                    return true;
0744:                // other keywords are not accepted.
0745:                if (SyntaxUtils.isKeyWord(id))
0746:                    return false;
0747:                if (!Character.isJavaIdentifierStart(id.charAt(0)))
0748:                    return false;
0749:                // todo: allow only "." and " " around points and javaIdPart
0750:                // no two points, ...
0751:
0752:                return true;
0753:            }
0754:
0755:            /** @return {name, params}  for example {String, null} as in "String" or {Vector, String} as in Vector<String>.
0756:             *    or {Class[], ?} as in "Class<?>[]"
0757:             */
0758:            public static String[] splitTypeParams(String tp) {
0759:                if (tp == null)
0760:                    return null;
0761:
0762:                int start = tp.indexOf('<');
0763:                if (start == -1)
0764:                    return new String[] { tp, null };
0765:                int end = tp.lastIndexOf('>');
0766:                if (end == -1)
0767:                    return new String[] { tp, null };
0768:
0769:                // [March2008] was false for Class<?>[], forgetting the array part !
0770:
0771:                return new String[] {
0772:                        tp.substring(0, start) + tp.substring(end + 1),
0773:                        tp.substring(start + 1, end) };
0774:
0775:            }
0776:
0777:            /** Removes all array [] elements at the end, including content
0778:             *  internal: remove everything after the first "[" occurence.
0779:             */
0780:            public static String removeAllArrayPartsAtEnd(String id) {
0781:                int pos = id.indexOf('[');
0782:                if (pos < 0)
0783:                    return id;
0784:                return id.substring(0, pos);
0785:            }
0786:
0787:            /** Removes the last array [ ] element at the end, including content
0788:             */
0789:            public static String removeLastArrayPartAtEnd(String id) {
0790:                int pos = id.lastIndexOf('[');
0791:                if (pos < 0)
0792:                    return id;
0793:                return id.substring(0, pos);
0794:            }
0795:
0796:            /** Map<Integer, List<A>> => Map.
0797:             *  the < and > must be balanced... uses first and lastindexof
0798:             */
0799:            public static String removeSingleTypeParameters(String id) {
0800:                int start = id.indexOf('<');
0801:                if (start < 0)
0802:                    return id;
0803:                int end = id.lastIndexOf('>');
0804:                if (end < 0)
0805:                    return id;
0806:                return id.substring(0, start) + id.substring(end + 1);
0807:            }
0808:
0809:            public static String getJavaNameSimpleIfLongForView(String jn) {
0810:                if (jn.length() < 30)
0811:                    return jn;
0812:                return makeSingleJavaNameSimple(jn);
0813:            }
0814:
0815:            /** Suitable for a single name, like java.lang.Object => Object.
0816:             */
0817:            public static String makeSingleJavaNameSimple(String jn) {
0818:                // [July2007]: used for abstract text generation, was failing for arrays.
0819:                if (jn.endsWith(";")) {
0820:                    jn = convertVmNameToFullJavaNames(jn);
0821:                }
0822:
0823:                // remove all generics parameter stuff  // [March2008]: failed for java.lang.Class<? extends java.lang.annotation.Annotation>. now works
0824:                int pos1 = jn.indexOf('<');
0825:                if (pos1 >= 0) {
0826:                    int pos2 = jn.indexOf('>', pos1);
0827:                    if (pos2 >= 0) {
0828:                        jn = jn.substring(0, pos1) + jn.substring(pos2 + 1);
0829:                    } else {
0830:                        System.out.println("??Bad syntax: " + jn);
0831:                    }
0832:                }
0833:
0834:                int posP = jn.lastIndexOf('.');
0835:                if (posP < 0)
0836:                    return jn;
0837:                return jn.substring(posP + 1);
0838:            }
0839:
0840:            /** java.lang.String hello(myApp.XYZ var) => String hello(XYZ var)
0841:             *  NOT ROBUST:
0842:             *   => only simplify if the guessed package name is lowercase.
0843:             *     => static method calls like String.hello remains unchanged
0844:             */
0845:            public static String makeAllJavaNamesSimpleInText(String signature) {
0846:                List<Integer> starts = new ArrayList<Integer>();
0847:                List<Integer> ends = new ArrayList<Integer>();
0848:                Matcher mat = javaAbsoluteIdentifierPattern.matcher(signature);
0849:                int lastStart = 0;
0850:
0851:                while (mat.find(lastStart)) {
0852:                    int start = mat.start();
0853:
0854:                    int end = mat.end();
0855:
0856:                    lastStart = end;
0857:
0858:                    if (Character.isUpperCase(signature.charAt(start)))
0859:                        continue;
0860:                    starts.add(start);
0861:                    ends.add(end);
0862:                }
0863:
0864:                StringBuilder ret = new StringBuilder(signature);
0865:                for (int i = starts.size() - 1; i >= 0; i--) // reverse to keep indices ! (can be boosted... directly in the first loop, but i'm lazy)
0866:                {
0867:                    String str = signature
0868:                            .substring(starts.get(i), ends.get(i));
0869:                    String rep = StringUtils.keepAfterLastExcl(str, ".");
0870:                    ret.replace(starts.get(i), ends.get(i), rep);
0871:                }
0872:
0873:                return ret.toString();
0874:            }
0875:
0876:            // don't start with a digit
0877:            final public static Pattern javaNamePattern = Pattern
0878:                    .compile("[a-zA-Z_][a-zA-Z_0-9]*");
0879:            // not working well: captures "tring.indexOf" !! => use javaNamePattern and filter the result using the first char instead...
0880:            //final public static Pattern javaNamePatternStartsLowercase = Pattern.compile("[a-z][a-zA-Z_0-9]*");
0881:
0882:            // recurse with points (at least one)
0883:            final public static Pattern javaAbsoluteIdentifierPattern = Pattern
0884:                    .compile(javaNamePattern + "(\\s*\\.\\s*" + javaNamePattern
0885:                            + ")+");
0886:
0887:            public static void main(String[] aa) {
0888:                System.out
0889:                        .println(removeAllContents(new StringBuilder(
0890:                                "Hello<String, List<String>> aa, double bb"),
0891:                                '<', '>'));
0892:                System.out.println("" + isInComment("123//*/abc", 7));
0893:
0894:                test_getJavaIdentifierBefore();
0895:                if (true)
0896:                    System.exit(0);
0897:
0898:                System.out.println(""
0899:                        + convertVmNameToFullJavaNames("[Ljava/lang/String;"));
0900:                System.out
0901:                        .println(""
0902:                                + Arrays
0903:                                        .toString(extractModifiersAndType("public  static   final strictfp void hello")));
0904:
0905:                System.out
0906:                        .println(""
0907:                                + removeSingleTypeParameters("Map<Integer, List<A>> a"));
0908:                System.out.println("" + removeLastArrayPartAtEnd("abc[3][2]"));
0909:                //System.out.println(makeAllJavaNamesSimple("Method checks to see if result of String.indexOf is positive, throws java.lang.Exception"));
0910:                //System.out.println(makeAllJavaNamesSimple("java.lang.String hello(mypack.XYZ var) throws String.hello() "));
0911:                //System.out.println(""+getArgumentNumberAtEnd("0,1,2, dd(3,3, ','),4"));
0912:                System.out.println(Arrays
0913:                        .toString(splitTypeParams("Vector<Vector<Object>>")));
0914:
0915:                /*List[] pos = parseSignatureAfterForJavaDoc (
0916:                      "/** Hallo * / public int[] hello(int a, double[ ] bb) {}", 5);*/
0917:
0918:                System.out.println("" + convertVmNameToFullJavaNames("[[I"));
0919:                System.out.println(""
0920:                        + convertVmNameToFullJavaNames("[Ljava.lang.Thread;"));
0921:
0922:                StringBuilder s = new StringBuilder("a(1)(22)()b(3)((1,(2)))");
0923:                removeAllContents(s, '(', ')');
0924:                System.out.println("" + s);
0925:
0926:            }
0927:
0928:            public static String createVariableNameFromClassName(String cn) {
0929:                if (SyntaxUtils.isKeyWord(cn)) {
0930:                    // int => i,double => d,...
0931:                    return "" + Character.toLowerCase(cn.charAt(0));
0932:                }
0933:                String varName = cn.replace('$', '_');
0934:
0935:                if (Character.isUpperCase(varName.charAt(0))) {
0936:                    varName = "" + Character.toLowerCase(varName.charAt(0))
0937:                            + varName.substring(1);
0938:                } else {
0939:                    varName = "_" + varName;
0940:                }
0941:                return varName;
0942:            }
0943:
0944:            /** [I => int[]  (defined in Class.getName()). Names are NOT also in simple form.
0945:             *   Used in the decompiledClass to match javap signatures !
0946:             *   Also used in JMapReader and JavaDocParser.
0947:             */
0948:            public static String convertVmNameToFullJavaNames(
0949:                    final String className) {
0950:                int depth = 0;
0951:                int i = 0;
0952:                for (; i < className.length(); i++) {
0953:                    if (className.charAt(i) == '[')
0954:                        depth++;
0955:                    else
0956:                        break;
0957:                }
0958:
0959:                if (depth == 0)
0960:                    return className;
0961:
0962:                String cn = className.substring(i);
0963:                StringBuilder sb = new StringBuilder();
0964:
0965:                if (cn.startsWith("L")) {
0966:                    sb.append(cn.substring(1, cn.length() - 1)); // also remove the ";" at end
0967:                } else {
0968:                    if (cn.length() == 1) {
0969:                        sb.append(getNameForVMNativeType(cn.charAt(0)));
0970:                    } else {
0971:                        sb.append("" + cn); // just a name, like java.lang.String
0972:                    }
0973:                }
0974:
0975:                // append array braces
0976:                for (i = 0; i < depth; i++) {
0977:                    sb.append("[]");
0978:                }
0979:                return sb.toString();
0980:            }
0981:
0982:            /**  I => int, ...
0983:             */
0984:            public static String getNameForVMNativeType(char charType) {
0985:                switch (charType) {
0986:                case 'I':
0987:                    return "int";
0988:                case 'B':
0989:                    return "byte";
0990:                case 'F':
0991:                    return "float";
0992:                case 'Z':
0993:                    return "boolean";
0994:                case 'S':
0995:                    return "short";
0996:                case 'D':
0997:                    return "double";
0998:                case 'J':
0999:                    return "long";
1000:                case 'C':
1001:                    return "char";
1002:                }
1003:                return "?? unknown native VM type " + charType;
1004:
1005:            }
1006:
1007:            /** java keywords up to 1.6 */
1008:            public static final TreeSet<String> javaKeywords = new TreeSet<String>(
1009:                    Arrays.asList(new String[] { "abstract", "boolean",
1010:                            "break", "byte", "case", "catch", "char", "class",
1011:                            "const", "continue", "default", "do", "double",
1012:                            "else", "extends", "final", "finally", "float",
1013:                            "for", "goto", "if", "implements", "import",
1014:                            "instanceof", "int", "interface", "long", "native",
1015:                            "new", "package", "private", "protected", "public",
1016:                            "return", "short", "static", "strictfp", "super",
1017:                            "switch", "synchronized", "this", "throw",
1018:                            "throws", "transient", "try", "void", "volatile",
1019:                            "while", "assert", // since 1.4
1020:                            "enum", // since 1.5
1021:                            "true", "false", "null" // not really keywords.., as null
1022:                    }));
1023:
1024:            public static boolean isKeyWord(String w) {
1025:                return javaKeywords.contains(w);
1026:            }
1027:
1028:            /** Also present in the javaKeywords
1029:             */
1030:            public static final TreeSet<String> primitiveTypes = new TreeSet<String>(
1031:                    Arrays
1032:                            .asList(new String[] { "boolean", "byte", "char",
1033:                                    "double", "float", "int", "long", "short",
1034:                                    "void" }));
1035:
1036:            /** Also present in the javaKeywords
1037:             */
1038:            public static final TreeSet<String> modifiers = new TreeSet<String>(
1039:                    Arrays
1040:                            .asList(new String[] { "abstract", "final",
1041:                                    "native", "private", "protected", "public",
1042:                                    "static", "strictfp", "synchronized",
1043:                                    "transient", "volatile" }));
1044:
1045:            /** if one of [boolean, float, ..., void]
1046:             */
1047:            public static boolean isPrimitiveType(String w) {
1048:                if (w == null)
1049:                    return false;
1050:                return primitiveTypes.contains(w);
1051:            }
1052:
1053:            public static boolean isModifier(String w) {
1054:                if (w == null)
1055:                    return false;
1056:                return modifiers.contains(w);
1057:            }
1058:
1059:            /** without generics parameters.
1060:             *  @return {mods, type}, type being empty if none found (for constructors)
1061:             *   type may have several items (as in "void hello")
1062:             */
1063:            public static String[] extractModifiersAndType(String modAndType) {
1064:                StringBuilder mods = new StringBuilder();
1065:                StringBuilder type = new StringBuilder();
1066:
1067:                //String type = "";
1068:                for (String mti : modAndType.split("\\s")) {
1069:                    if (isModifier(mti)) {
1070:                        mods.append(mti);
1071:                        mods.append(" ");
1072:                    } else {
1073:                        type.append(mti);
1074:                        type.append(" ");
1075:                    }
1076:                }
1077:
1078:                return new String[] { mods.toString().trim(),
1079:                        type.toString().trim() };
1080:            }
1081:
1082:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.