From 9fe0a4de45a8d7a965a38aec552a9b5236d02165 Mon Sep 17 00:00:00 2001 From: lhark Date: Sat, 12 Dec 2015 22:50:14 +0100 Subject: [PATCH] Plugins update --- vim/autoload/Reflection.java | 670 ------ vim/autoload/java_parser.vim | 3500 ------------------------------- vim/autoload/javacomplete.vim | 2932 -------------------------- vim/bundle/Vundle.vim | 2 +- vim/bundle/ctrlp.vim | 2 +- vim/bundle/mirodark | 1 - vim/bundle/molokai | 1 - vim/bundle/nerdtree | 2 +- vim/bundle/undotree | 2 +- vim/bundle/vim-easymotion | 2 +- vim/bundle/vim-multiple-cursors | 2 +- vim/bundle/vim-perl | 2 +- vim/bundle/vim-startify | 2 +- 13 files changed, 8 insertions(+), 7112 deletions(-) delete mode 100644 vim/autoload/Reflection.java delete mode 100644 vim/autoload/java_parser.vim delete mode 100644 vim/autoload/javacomplete.vim delete mode 160000 vim/bundle/mirodark delete mode 160000 vim/bundle/molokai diff --git a/vim/autoload/Reflection.java b/vim/autoload/Reflection.java deleted file mode 100644 index 5452b0f..0000000 --- a/vim/autoload/Reflection.java +++ /dev/null @@ -1,670 +0,0 @@ -/** - * Reflection.java - * - * A utility class for javacomplete mainly for reading class or package information. - * Version: 0.77 - * Maintainer: cheng fang - * Last Change: 2007-09-16 - * Copyright: Copyright (C) 2007 cheng fang. All rights reserved. - * License: Vim License (see vim's :help license) - * - */ - -import java.lang.reflect.*; -import java.io.*; -import java.util.*; -import java.util.zip.*; - -class Reflection { - static final String VERSION = "0.77"; - - static final int OPTION_FIELD = 1; - static final int OPTION_METHOD = 2; - static final int OPTION_STATIC_FIELD = 4; - static final int OPTION_STATIC_METHOD = 8; - static final int OPTION_CONSTRUCTOR = 16; - static final int OPTION_STATIC = 12; // compound static - static final int OPTION_INSTANCE = 15; // compound instance - static final int OPTION_ALL = 31; // compound all - static final int OPTION_SUPER = 32; - static final int OPTION_SAME_PACKAGE = 64; - - static final int STRATEGY_ALPHABETIC = 128; - static final int STRATEGY_HIERARCHY = 256; - static final int STRATEGY_DEFAULT = 512; - - static final int RETURN_ALL_PACKAGE_INFO = 0x1000; - - static final String KEY_NAME = "'n':"; // "'name':"; - static final String KEY_TYPE = "'t':"; // "'type':"; - static final String KEY_MODIFIER = "'m':"; // "'modifier':"; - static final String KEY_PARAMETERTYPES = "'p':"; // "'parameterTypes':"; - static final String KEY_RETURNTYPE = "'r':"; // "'returnType':"; - static final String KEY_DESCRIPTION = "'d':"; // "'description':"; - static final String KEY_DECLARING_CLASS = "'c':"; // "'declaringclass':"; - - static final String NEWLINE = ""; // "\r\n" - - static boolean debug_mode = false; - - static Hashtable htClasspath = new Hashtable(); - - public static boolean existed(String fqn) { - boolean result = false; - try { - Class.forName(fqn); - result = true; - } - catch (Exception ex) { - } - return result; - } - - public static String existedAndRead(String fqns) { - Hashtable mapPackages = new Hashtable(); // qualified name --> StringBuffer - Hashtable mapClasses = new Hashtable(); // qualified name --> StringBuffer - - for (StringTokenizer st = new StringTokenizer(fqns, ","); st.hasMoreTokens(); ) { - String fqn = st.nextToken(); - try { - Class clazz = Class.forName(fqn); - putClassInfo(mapClasses, clazz); - } - catch (Exception ex) { - String binaryName = fqn; - boolean found = false; - while (true) { - try { - int lastDotPos = binaryName.lastIndexOf('.'); - if (lastDotPos == -1) - break; - binaryName = binaryName.substring(0, lastDotPos) + '$' + binaryName.substring(lastDotPos+1, binaryName.length()); - Class clazz = Class.forName(binaryName); - putClassInfo(mapClasses, clazz); - found = true; - break; - } - catch (Exception e) { - } - } - if (!found) - putPackageInfo(mapPackages, fqn); - } - } - - if (mapPackages.size() > 0 || mapClasses.size() > 0) { - StringBuffer sb = new StringBuffer(4096); - sb.append("{"); - for (Enumeration e = mapPackages.keys(); e.hasMoreElements(); ) { - String s = (String)e.nextElement(); - sb.append("'").append( s.replace('$', '.') ).append("':").append(mapPackages.get(s)).append(","); - } - for (Enumeration e = mapClasses.keys(); e.hasMoreElements(); ) { - String s = (String)e.nextElement(); - sb.append("'").append( s.replace('$', '.') ).append("':").append(mapClasses.get(s)).append(","); - } - sb.append("}"); - return sb.toString(); - } - else - return ""; - } - - private static String getPackageList(String fqn) { - Hashtable mapPackages = new Hashtable(); - putPackageInfo(mapPackages, fqn); - return mapPackages.size() > 0 ? mapPackages.get(fqn).toString() : ""; - } - - private static Hashtable collectClassPath() { - if (!htClasspath.isEmpty()) - return htClasspath; - - // runtime classes - if ("Kaffe".equals(System.getProperty("java.vm.name"))) { - addClasspathesFromDir(System.getProperty("java.home") + File.separator + "share" + File.separator + "kaffe" + File.separator); - } - else if ("GNU libgcj".equals(System.getProperty("java.vm.name"))) { - if (new File(System.getProperty("sun.boot.class.path")).exists()) - htClasspath.put(System.getProperty("sun.boot.class.path"), ""); - } - - if (System.getProperty("java.vendor").toLowerCase(Locale.US).indexOf("microsoft") >= 0) { - // `*.ZIP` files in `Packages` directory - addClasspathesFromDir(System.getProperty("java.home") + File.separator + "Packages" + File.separator); - } - else { - // the following code works for several kinds of JDK - // - JDK1.1: classes.zip - // - JDK1.2+: rt.jar - // - JDK1.4+ of Sun and Apple: rt.jar + jce.jar + jsse.jar - // - JDK1.4 of IBM split rt.jar into core.jar, graphics.jar, server.jar - // combined jce.jar and jsse.jar into security.jar - // - JDK for MacOS X split rt.jar into classes.jar, ui.jar in Classes directory - addClasspathesFromDir(System.getProperty("java.home") + File.separator + "lib" + File.separator); - addClasspathesFromDir(System.getProperty("java.home") + File.separator + "jre" + File.separator + "lib" + File.separator); - addClasspathesFromDir(System.getProperty("java.home") + File.separator + ".." + File.separator + "Classes" + File.separator); - } - - // ext - String extdirs = System.getProperty("java.ext.dirs"); - for (StringTokenizer st = new StringTokenizer(extdirs, File.pathSeparator); st.hasMoreTokens(); ) { - addClasspathesFromDir(st.nextToken() + File.separator); - } - - // user classpath - String classPath = System.getProperty("java.class.path"); - StringTokenizer st = new StringTokenizer(classPath, File.pathSeparator); - while (st.hasMoreTokens()) { - String path = st.nextToken(); - File f = new File(path); - if (!f.exists()) - continue; - - if (path.endsWith(".jar") || path.endsWith(".zip")) - htClasspath.put(f.toString(), ""); - else { - if (f.isDirectory()) - htClasspath.put(f.toString(), ""); - } - } - - return htClasspath; - } - - private static void addClasspathesFromDir(String dirpath) { - File dir = new File(dirpath); - if (dir.isDirectory()) { - String[] items = dir.list(); // use list() instead of listFiles() since the latter are introduced in 1.2 - for (int i = 0; i < items.length; i++) { - File f = new File(dirpath + items[i]); - if (!f.exists()) - continue; - - if (items[i].endsWith(".jar") || items[i].endsWith(".zip") || items[i].endsWith(".ZIP")) { - htClasspath.put(f.toString(), ""); - } - else if (items.equals("classes")) { - if (f.isDirectory()) - htClasspath.put(f.toString(), ""); - } - } - } - } - - - /** - * If name is empty, put all loadable package info into map once. - */ - private static void putPackageInfo(Hashtable map, String name) { - String prefix = name.replace('.', '/') + "/"; - Hashtable subpackages = new Hashtable(); - Hashtable classes = new Hashtable(); - for (Enumeration e = collectClassPath().keys(); e.hasMoreElements(); ) { - String path = (String)e.nextElement(); - if (path.endsWith(".jar") || path.endsWith(".zip")) - appendListFromJar(subpackages, classes, path, prefix); - else - appendListFromFolder(subpackages, classes, path, prefix); - } - - if (subpackages.size() > 0 || classes.size() > 0) { - StringBuffer sb = new StringBuffer(1024); - sb.append("{'tag':'PACKAGE','subpackages':["); - for (Enumeration e = subpackages.keys(); e.hasMoreElements(); ) { - sb.append("'").append(e.nextElement()).append("',"); - } - sb.append("],'classes':["); - for (Enumeration e = classes.keys(); e.hasMoreElements(); ) { - sb.append("'").append(e.nextElement()).append("',"); - } - sb.append("]}"); - map.put(name, sb.toString()); - } - } - - public static void appendListFromJar(Hashtable subpackages, Hashtable classes, String path, String prefix) { - try { - for (Enumeration entries = new ZipFile(path).entries(); entries.hasMoreElements(); ) { - String entry = entries.nextElement().toString(); - int len = entry.length(); - if (entry.endsWith(".class") && entry.indexOf('$') == -1 - && entry.startsWith(prefix)) { - int splitPos = entry.indexOf('/', prefix.length()); - String shortname = entry.substring(prefix.length(), splitPos == -1 ? entry.length()-6 : splitPos); - if (splitPos == -1) { - if (!classes.containsKey(shortname)) - classes.put(shortname, ""); //classes.put(shortname, "{'tag':'CLASSDEF','name':'"+shortname+"'}"); - } - else { - if (!subpackages.containsKey(shortname)) - subpackages.put(shortname, ""); //subpackages.put(shortname, "{'tag':'PACKAGE','name':'" +shortname+"'}"); - } - } - } - } - catch (Throwable e) { - //e.printStackTrace(); - } - } - - public static void appendListFromFolder(Hashtable subpackages, Hashtable classes, String path, String prefix) { - try { - String fullPath = path + "/" + prefix; - File file = new File(fullPath); - if (file.isDirectory()) { - String[] descents = file.list(); - for (int i = 0; i < descents.length; i++) { - if (descents[i].indexOf('$') == -1) { - if (descents[i].endsWith(".class")) { - String shortname = descents[i].substring(0, descents[i].length()-6); - if (!classes.containsKey(shortname)) - classes.put(shortname, ""); - } - else if ((new File(fullPath + "/" + descents[i])).isDirectory()) { - if (!subpackages.containsKey(descents[i])) - subpackages.put(descents[i], ""); - } - } - } - } - } - catch (Throwable e) { - } - } - - private static int INDEX_PACKAGE = 0; - private static int INDEX_CLASS = 1; - - // generate information of all packages in jar files. - public static String getPackageList() { - Hashtable map = new Hashtable(); - - for (Enumeration e = collectClassPath().keys(); e.hasMoreElements(); ) { - String path = (String)e.nextElement(); - if (path.endsWith(".jar") || path.endsWith(".zip")) - appendListFromJar(path, map); - } - - StringBuffer sb = new StringBuffer(4096); - sb.append("{"); - //sb.append("'*':'").append( map.remove("") ).append("',"); // default package - for (Enumeration e = map.keys(); e.hasMoreElements(); ) { - String s = (String)e.nextElement(); - StringBuffer[] sbs = (StringBuffer[])map.get(s); - sb.append("'").append( s.replace('/', '.') ).append("':") - .append("{'tag':'PACKAGE'"); - if (sbs[INDEX_PACKAGE].length() > 0) - sb.append(",'subpackages':[").append(sbs[INDEX_PACKAGE]).append("]"); - if (sbs[INDEX_CLASS].length() > 0) - sb.append(",'classes':[").append(sbs[INDEX_CLASS]).append("]"); - sb.append("},"); - } - sb.append("}"); - return sb.toString(); - - } - - public static void appendListFromJar(String path, Hashtable map) { - try { - for (Enumeration entries = new ZipFile(path).entries(); entries.hasMoreElements(); ) { - String entry = entries.nextElement().toString(); - int len = entry.length(); - if (entry.endsWith(".class") && entry.indexOf('$') == -1) { - int slashpos = entry.lastIndexOf('/'); - String parent = entry.substring(0, slashpos); - String child = entry.substring(slashpos+1, len-6); - putItem(map, parent, child, INDEX_CLASS); - - slashpos = parent.lastIndexOf('/'); - if (slashpos != -1) { - AddToParent(map, parent.substring(0, slashpos), parent.substring(slashpos+1)); - } - } - } - } - catch (Throwable e) { - //e.printStackTrace(); - } - } - - public static void putItem(Hashtable map, String parent, String child, int index) { - StringBuffer[] sbs = (StringBuffer[])map.get(parent); - if (sbs == null) { - sbs = new StringBuffer[] { new StringBuffer(256), // packages - new StringBuffer(256) // classes - }; - } - if (sbs[index].toString().indexOf("'" + child + "',") == -1) - sbs[index].append("'").append(child).append("',"); - map.put(parent, sbs); - } - - public static void AddToParent(Hashtable map, String parent, String child) { - putItem(map, parent, child, INDEX_PACKAGE); - - int slashpos = parent.lastIndexOf('/'); - if (slashpos != -1) { - AddToParent(map, parent.substring(0, slashpos), parent.substring(slashpos+1)); - } - } - - - public static String getClassInfo(String className) { - Hashtable mapClasses = new Hashtable(); - try { - Class clazz = Class.forName(className); - putClassInfo(mapClasses, clazz); - } - catch (Exception ex) { - } - - if (mapClasses.size() == 1) { - return mapClasses.get(className).toString(); // return {...} - } - else if (mapClasses.size() > 1) { - StringBuffer sb = new StringBuffer(4096); - sb.append("["); - for (Enumeration e = mapClasses.keys(); e.hasMoreElements(); ) { - String s = (String)e.nextElement(); - sb.append(mapClasses.get(s)).append(","); - } - sb.append("]"); - return sb.toString(); // return [...] - } - else - return ""; - } - - private static void putClassInfo(Hashtable map, Class clazz) { - if (map.containsKey(clazz.getName())) - return ; - - try { - StringBuffer sb = new StringBuffer(1024); - sb.append("{") - .append("'tag':'CLASSDEF',").append(NEWLINE) - .append("'flags':'").append(Integer.toString(clazz.getModifiers(), 2)).append("',").append(NEWLINE) - .append("'name':'").append(clazz.getName().replace('$', '.')).append("',").append(NEWLINE) - //.append("'package':'").append(clazz.getPackage().getName()).append("',").append(NEWLINE) // no getPackage() in JDK1.1 - .append("'classpath':'1',").append(NEWLINE) - .append("'fqn':'").append(clazz.getName().replace('$', '.')).append("',").append(NEWLINE); - - Class[] interfaces = clazz.getInterfaces(); - if (clazz.isInterface()) { - sb.append("'extends':["); - } else { - Class superclass = clazz.getSuperclass(); - if (superclass != null && !"java.lang.Object".equals(superclass.getName())) { - sb.append("'extends':['").append(superclass.getName().replace('$', '.')).append("'],").append(NEWLINE); - putClassInfo(map, superclass); // !! - } - sb.append("'implements':["); - } - for (int i = 0, n = interfaces.length; i < n; i++) { - sb.append("'").append(interfaces[i].getName().replace('$', '.')).append("',"); - putClassInfo(map, interfaces[i]); // !! - } - sb.append("],").append(NEWLINE);; - - Constructor[] ctors = clazz.getConstructors(); - sb.append("'ctors':["); - for (int i = 0, n = ctors.length; i < n; i++) { - Constructor ctor = ctors[i]; - sb.append("{"); - appendModifier(sb, ctor.getModifiers()); - appendParameterTypes(sb, ctor.getParameterTypes()); - sb.append(KEY_DESCRIPTION).append("'").append(ctors[i].toString()).append("'"); - sb.append("},").append(NEWLINE); - } - sb.append("], ").append(NEWLINE); - - Field[] fields = clazz.getFields(); - //java.util.Arrays.sort(fields, comparator); - sb.append("'fields':["); - for (int i = 0, n = fields.length; i < n; i++) { - Field f = fields[i]; - int modifier = f.getModifiers(); - sb.append("{"); - sb.append(KEY_NAME).append("'").append(f.getName()).append("',"); - if (!f.getDeclaringClass().getName().equals(clazz.getName())) - sb.append(KEY_DECLARING_CLASS).append("'").append(f.getDeclaringClass().getName()).append("',"); - appendModifier(sb, modifier); - sb.append(KEY_TYPE).append("'").append(f.getType().getName()).append("'"); - sb.append("},").append(NEWLINE); - } - sb.append("], ").append(NEWLINE); - - Method[] methods = clazz.getMethods(); - //java.util.Arrays.sort(methods, comparator); - sb.append("'methods':["); - for (int i = 0, n = methods.length; i < n; i++) { - Method m = methods[i]; - int modifier = m.getModifiers(); - sb.append("{"); - sb.append(KEY_NAME).append("'").append(m.getName()).append("',"); - if (!m.getDeclaringClass().getName().equals(clazz.getName())) - sb.append(KEY_DECLARING_CLASS).append("'").append(m.getDeclaringClass().getName()).append("',"); - appendModifier(sb, modifier); - sb.append(KEY_RETURNTYPE).append("'").append(m.getReturnType().getName()).append("',"); - appendParameterTypes(sb, m.getParameterTypes()); - sb.append(KEY_DESCRIPTION).append("'").append(m.toString()).append("'"); - sb.append("},").append(NEWLINE); - } - sb.append("], ").append(NEWLINE); - - Class[] classes = clazz.getClasses(); - sb.append("'classes': ["); - for (int i = 0, n = classes.length; i < n; i++) { - Class c = classes[i]; - sb.append("'").append(c.getName().replace('$', '.')).append("',"); - putClassInfo(map, c); // !! - } - sb.append("], ").append(NEWLINE); - - appendDeclaredMembers(map, clazz, sb); - - sb.append("}"); - map.put(clazz.getName(), sb); - } - catch (Exception ex) { - //ex.printStackTrace(); - } - } - - private static void appendDeclaredMembers(Hashtable map, Class clazz, StringBuffer sb) { - Constructor[] ctors = clazz.getDeclaredConstructors(); - sb.append("'declared_ctors':["); - for (int i = 0, n = ctors.length; i < n; i++) { - Constructor ctor = ctors[i]; - if (!Modifier.isPublic(ctor.getModifiers())) { - sb.append("{"); - appendModifier(sb, ctor.getModifiers()); - appendParameterTypes(sb, ctor.getParameterTypes()); - sb.append(KEY_DESCRIPTION).append("'").append(ctors[i].toString()).append("'"); - sb.append("},").append(NEWLINE); - } - } - sb.append("], ").append(NEWLINE); - - Field[] fields = clazz.getDeclaredFields(); - sb.append("'declared_fields':["); - for (int i = 0, n = fields.length; i < n; i++) { - Field f = fields[i]; - int modifier = f.getModifiers(); - if (!Modifier.isPublic(modifier)) { - sb.append("{"); - sb.append(KEY_NAME).append("'").append(f.getName()).append("',"); - if (!f.getDeclaringClass().getName().equals(clazz.getName())) - sb.append(KEY_DECLARING_CLASS).append("'").append(f.getDeclaringClass().getName()).append("',"); - appendModifier(sb, modifier); - sb.append(KEY_TYPE).append("'").append(f.getType().getName()).append("'"); - sb.append("},").append(NEWLINE); - } - } - sb.append("], ").append(NEWLINE); - - Method[] methods = clazz.getDeclaredMethods(); - sb.append("'declared_methods':["); - for (int i = 0, n = methods.length; i < n; i++) { - Method m = methods[i]; - int modifier = m.getModifiers(); - if (!Modifier.isPublic(modifier)) { - sb.append("{"); - sb.append(KEY_NAME).append("'").append(m.getName()).append("',"); - if (!m.getDeclaringClass().getName().equals(clazz.getName())) - sb.append(KEY_DECLARING_CLASS).append("'").append(m.getDeclaringClass().getName()).append("',"); - appendModifier(sb, modifier); - sb.append(KEY_RETURNTYPE).append("'").append(m.getReturnType().getName()).append("',"); - appendParameterTypes(sb, m.getParameterTypes()); - sb.append(KEY_DESCRIPTION).append("'").append(m.toString()).append("'"); - sb.append("},").append(NEWLINE); - } - } - sb.append("], ").append(NEWLINE); - - Class[] classes = clazz.getDeclaredClasses(); - sb.append("'declared_classes': ["); - for (int i = 0, n = classes.length; i < n; i++) { - Class c = classes[i]; - if (!Modifier.isPublic(c.getModifiers())) { - sb.append("'").append(c.getName().replace('$', '.')).append("',"); - putClassInfo(map, c); // !! - } - } - sb.append("], ").append(NEWLINE); - } - - private static void appendModifier(StringBuffer sb, int modifier) { - sb.append(KEY_MODIFIER).append("'").append(Integer.toString(modifier, 2)).append("', "); - } - - private static void appendParameterTypes(StringBuffer sb, Class[] paramTypes) { - if (paramTypes.length == 0) return ; - - sb.append(KEY_PARAMETERTYPES).append("["); - for (int j = 0; j < paramTypes.length; j++) { - sb.append("'").append(paramTypes[j].getName()).append("',"); - } - sb.append("],"); - } - - private static boolean isBlank(String str) { - int len; - if (str == null || (len = str.length()) == 0) - return true; - for (int i = 0; i < len; i++) - if ((Character.isWhitespace(str.charAt(i)) == false)) - return false; - return true; - } - - // test methods - - static void debug(String s) { - if (debug_mode) - System.out.println(s); - } - static void output(String s) { - if (!debug_mode) - System.out.print(s); - } - - - private static void usage() { - System.out.println("Reflection for javacomplete (" + VERSION + ")"); - System.out.println(" java [-classpath] Reflection [-c] [-d] [-e] [-h] [-v] [-p] [-s] name[,comma_separated_name_list]"); - System.out.println("Options:"); - System.out.println(" -a list all members in alphabetic order"); - System.out.println(" -c list constructors"); - System.out.println(" -C return class info"); - System.out.println(" -d default strategy, i.e. instance fields, instance methods, static fields, static methods"); - System.out.println(" -e check class existed"); - System.out.println(" -E check class existed and read class information"); - System.out.println(" -D debug mode"); - System.out.println(" -p list package content"); - System.out.println(" -P print all package info in the Vim dictionary format"); - System.out.println(" -s list static fields and methods"); - System.out.println(" -h help"); - System.out.println(" -v version"); - } - - public static void main(String[] args) { - String className = null; - int option = 0x0; - boolean wholeClassInfo = false; - boolean onlyStatic = false; - boolean onlyConstructor = false; - boolean listPackageContent = false; - boolean checkExisted = false; - boolean checkExistedAndRead = false; - boolean allPackageInfo = false; - - for (int i = 0, n = args.length; i < n && !isBlank(args[i]); i++) { - //debug(args[i]); - if (args[i].charAt(0) == '-') { - if (args[i].length() > 1) { - switch (args[i].charAt(1)) { - case 'a': - break; - case 'c': // request constructors - option = option | OPTION_CONSTRUCTOR; - onlyConstructor = true; - break; - case 'C': // class info - wholeClassInfo = true; - break; - case 'd': // default strategy - option = option | STRATEGY_DEFAULT; - break; - case 'D': // debug mode - debug_mode = true; - break; - case 'e': // class existed - checkExisted = true; - break; - case 'E': // check existed and read class information - checkExistedAndRead = true; - break; - case 'h': // help - usage(); - return ; - case 'v': // version - System.out.println("Reflection for javacomplete (" + VERSION + ")"); - break; - case 'p': - listPackageContent = true; - break; - case 'P': - option = RETURN_ALL_PACKAGE_INFO; - break; - case 's': // request static members - option = option | OPTION_STATIC_METHOD | OPTION_STATIC_FIELD; - onlyStatic = true; - break; - default: - } - } - } - else { - className = args[i]; - } - } - if (className == null && (option & RETURN_ALL_PACKAGE_INFO) != RETURN_ALL_PACKAGE_INFO) { - return; - } - if (option == 0x0) - option = OPTION_INSTANCE; - - if (wholeClassInfo) - output( getClassInfo(className) ); - else if ((option & RETURN_ALL_PACKAGE_INFO) == RETURN_ALL_PACKAGE_INFO) - output( getPackageList() ); - else if (checkExistedAndRead) - output( existedAndRead(className) ); - else if (checkExisted) - output( String.valueOf(existed(className)) ); - else if (listPackageContent) - output( getPackageList(className) ); - } -} diff --git a/vim/autoload/java_parser.vim b/vim/autoload/java_parser.vim deleted file mode 100644 index 5e1ec38..0000000 --- a/vim/autoload/java_parser.vim +++ /dev/null @@ -1,3500 +0,0 @@ -" Vim autoload script for a JAVA PARSER and more. -" Language: Java -" Maintainer: cheng fang -" Last Changed: 2007-09-16 -" Version: 0.67 -" Copyright: Copyright (C) 2007 cheng fang. All rights reserved. -" License: Vim License (see vim's :help license) - - -if exists("g:loaded_javaparser") || version < 700 || &cp - finish -endif -let g:loaded_javaparser = 'v0.67' - - -" Constants used by scanner and parser {{{1 -let s:EOI = '' - -let s:keywords = {'+': 'PLUS', '-': 'SUB', '!': 'BANG', '%': 'PERCENT', '^': 'CARET', '&': 'AMP', '*': 'STAR', '|': 'BAR', '~': 'TILDE', '/': 'SLASH', '>': 'GT', '<': 'LT', '?': 'QUES', ':': 'COLON', '=': 'EQ', '++': 'PLUSPLUS', '--': 'SUBSUB', '==': 'EQEQ', '<=': 'LTEQ', '>=': 'GTEQ', '!=': 'BANGEQ', '<<': 'LTLT', '>>': 'GTGT', '>>>': 'GTGTGT', '+=': 'PLUSEQ', '-=': 'SUBEQ', '*=': 'STAREQ', '/=': 'SLASHEQ', '&=': 'AMPEQ', '|=': 'BAREQ', '^=': 'CARETEQ', '%=': 'PERCENTEQ', '<<=': 'LTLTEQ', '>>=': 'GTGTEQ', '>>>=': 'GTGTGTEQ', '||': 'BARBAR', '&&': 'AMPAMP', 'abstract': 'ABSTRACT', 'assert': 'ASSERT', 'boolean': 'BOOLEAN', 'break': 'BREAK', 'byte': 'BYTE', 'case': 'CASE', 'catch': 'CATCH', 'char': 'CHAR', 'class': 'CLASS', 'const': 'CONST', 'continue': 'CONTINUE', 'default': 'DEFAULT', 'do': 'DO', 'double': 'DOUBLE', 'else': 'ELSE', 'extends': 'EXTENDS', 'final': 'FINAL', 'finally': 'FINALLY', 'float': 'FLOAT', 'for': 'FOR', 'goto': 'GOTO', 'if': 'IF', 'implements': 'IMPLEMENTS', 'import': 'IMPORT', 'instanceof': 'INSTANCEOF', 'int': 'INT', 'interface': 'INTERFACE', 'long': 'LONG', 'native': 'NATIVE', 'new': 'NEW', 'package': 'PACKAGE', 'private': 'PRIVATE', 'protected': 'PROTECTED', 'public': 'PUBLIC', 'return': 'RETURN', 'short': 'SHORT', 'static': 'STATIC', 'strictfp': 'STRICTFP', 'super': 'SUPER', 'switch': 'SWITCH', 'synchronized': 'SYNCHRONIZED', 'this': 'THIS', 'throw': 'THROW', 'throws': 'THROWS', 'transient': 'TRANSIENT', 'try': 'TRY', 'void': 'VOID', 'volatile': 'VOLATILE', 'while': 'WHILE', 'true': 'TRUE', 'false': 'FALSE', 'null': 'NULL', '(': 'LPAREN', ')': 'RPAREN', '{': 'LBRACE', '}': 'RBRACE', '[': 'LBRACKET', ']': 'RBRACKET', ';': 'SEMI', ',': 'COMMA', '.': 'DOT', 'enum': 'ENUM', '...': 'ELLIPSIS', '@': 'MONKEYS_AT'} - -let s:Flags = {'PUBLIC': 0x1, 'PRIVATE': 0x2, 'PROTECTED': 0x4, 'STATIC': 0x8, 'FINAL': 0x10, 'SYNCHRONIZED': 0x20, 'VOLATILE': 0x40, 'TRANSIENT': 0x80, 'NATIVE': 0x100, 'INTERFACE': 0x200, 'ABSTRACT': 0x400, 'STRICTFP': 0x800, 'SYNTHETIC': 0x1000, 'ANNOTATION': 0x2000, 'ENUM': 0x4000, 'StandardFlags':0x0fff, 'ACC_SUPER': 0x20, 'ACC_BRIDGE': 0x40, 'ACC_VARARGS': 0x80, 'DEPRECATED': 0x20000, 'HASINIT': 0x40000, 'BLOCK': 0x100000, 'IPROXY': 0x200000, 'NOOUTERTHIS': 0x400000, 'EXISTS': 0x800000, 'COMPOUND': 0x1000000, 'CLASS_SEEN': 0x2000000, 'SOURCE_SEEN': 0x4000000, 'LOCKED': 0x8000000, 'UNATTRIBUTED': 0x10000000, 'ANONCONSTR': 0x20000000, 'ACYCLIC': 0x40000000, 'BRIDGE': 1.repeat('0', 31), 'PARAMETER': 1.repeat('0', 33), 'VARARGS': 1.repeat('0', 34), 'ACYCLIC_ANN': 1.repeat('0', 35), 'GENERATEDCONSTR': 1.repeat('0', 36), 'HYPOTHETICAL': 1.repeat('0', 37), 'PROPRIETARY': 1.repeat('0', 38)} - -let s:RE_ANYTHING_AND_NEWLINE = '\(\(.\|\n\)*\)' -let s:RE_LINE_COMMENT = '//.*$' -let s:RE_COMMENT_SP = '/\*\*/' -let s:RE_COMMENT = '' -let s:RE_BRACKETS = '\(\s*\[\s*\]\)' - -let s:RE_IDENTIFIER = '[a-zA-Z_$][a-zA-Z0-9_$]*' -let s:RE_QUALID = s:RE_IDENTIFIER. '\(\s*\.\s*' .s:RE_IDENTIFIER. '\)*' -let s:RE_TYPE_NAME = s:RE_QUALID -let s:RE_REFERENCE_TYPE = s:RE_QUALID . s:RE_BRACKETS . '*' " TypeName || Type[] -let s:RE_TYPE = s:RE_REFERENCE_TYPE " PrimitiveType || ReferenceType -let s:RE_TYPE_VARIABLE = s:RE_IDENTIFIER -let s:RE_VAR_DECL_ID = s:RE_IDENTIFIER . s:RE_BRACKETS . '*' - -let s:RE_TYPE_PARAMS = '' - -let s:RE_THROWS = 'throws\s\+' . s:RE_TYPE_NAME . '\(\s*,\s*' . s:RE_TYPE_NAME . '\)*' -let s:RE_FORMAL_PARAM = '\(final\s*\)\='. s:RE_TYPE . '\s\+' . s:RE_VAR_DECL_ID -let s:RE_FORMAL_PARAM_LIST = s:RE_FORMAL_PARAM . '\(\s*,\s*' . s:RE_FORMAL_PARAM . '\)*' -let s:RE_FORMAL_PARAM2 = '^\s*\(final\s*\)\=\('. s:RE_TYPE . '\)\s\+\(' . s:RE_IDENTIFIER . '\)' . s:RE_BRACKETS . '*' - -let s:RE_MEMBER_MODS = '\%(PUBLIC\|PROTECTED\|PRIVATE\|ABSTRACT\|STATIC\|FINAL\|TRANSIENT\|VOLATILE\|SYNCHRONIZED\|NATIVE\|STRICTFP\)' -let s:RE_MEMBER_HEADER = '\s*\(\%(' .s:RE_MEMBER_MODS. '\s\+\)\+\)\(' .s:RE_IDENTIFIER. '\%(\s*\.\s*' .s:RE_IDENTIFIER. '\)*\%(\s*\[\s*\]\)*\)\s\+\(' .s:RE_IDENTIFIER. '\)' - -" API {{{1 - -let s:PROTOTYPE = {'s:options': {}, 'b:buf': '', 'b:buflen': 0, 'b:lines': [], 'b:idxes': [0], 'b:bp': -1, 'b:ch': '', 'b:line': 0, 'b:col': 0, 'b:pos': 0, 'b:endPos': 0, 'b:prevEndPos': 0, 'b:errPos': -1, 'b:errorEndPos': -1, 'b:sbuf': '', 'b:name': '', 'b:token': '', 'b:docComment': '', 'b:radix': 0, 'b:unicodeConversionBp': -1, 'b:scanStrategy': 0, 'b:allowGenerics': 1, 'b:allowVarargs': 1, 'b:allowAsserts': 1, 'b:allowEnums': 1, 'b:allowForeach': 1, 'b:allowStaticImport': 1, 'b:allowAnnotations': 1, 'b:keepDocComments': 1, 'b:mode': 0, 'b:lastmode': 0, 'b:log': [], 'b:et_perf': '', 'b:et_nextToken_count': 0} - -" Function to initialize the parser -" parameters: -" - lines List of code text -" - options A set of options -fu! java_parser#InitParser(lines, ...) - let s:options = a:0 == 0 ? {} : a:1 - - " internal variables for scanning -" let b:buf = '' " The input buffer - let b:buflen = 0 " index of one past last character in buffer. also eofPos - let b:lines = a:lines " The input buffer - let b:idxes = [0] " Begin index of every lines - let b:bp = -1 " index of next character to be read. - let b:ch = '' " The current character. - let b:line = 0 " The line number position of the current character. - let b:col = 0 " The column number position of the current character. - let b:pos = 0 " The token's position, 0-based offset from beginning of text. - let b:endPos = 0 " Character position just after the last character of the token. - let b:prevEndPos = 0 " The last character position of the previous token. - let b:errPos = -1 " The position where a lexical error occurred - let b:errorEndPos = -1 " - let b:sbuf = '' " A character buffer for literals. - let b:name = '' " The name of an identifier or token: - let b:token = 0 " The token, set by s:nextToken(). - let b:docComment = '' - let b:radix = 0 " The radix of a numeric literal token. - let b:unicodeConversionBp =-1 " The buffer index of the last converted unicode character - - let b:scanStrategy = get(s:options, 'scanStrategy', -1) " 0 - only class members when parse full file; - " 1 - keep statement as a whole string; - " 2 - all - " -1 - enable quick recognition of declarations in common form. - - " language feature options. - let b:allowGenerics = get(s:options, 'allowGenerics', 1) - let b:allowVarargs = get(s:options, 'allowVarargs', 1) - let b:allowAsserts = get(s:options, 'allowAsserts', 1) - let b:allowEnums = get(s:options, 'allowEnums', 1) - let b:allowForeach = get(s:options, 'allowForeach', 1) - let b:allowStaticImport = get(s:options, 'allowStaticImport', 1) - let b:allowAnnotations = get(s:options, 'allowAnnotations', 1) - let b:keepDocComments = get(s:options, 'keepDocComments', 1) - - let b:mode = 0 " The current mode. - let b:lastmode = 0 " The mode of the term that was parsed last. - - - let b:log = [] - - let b:et_perf = '' - let b:et_nextToken_count = 0 - -" let b:buf = join(a:lines, "\r") -" let b:buflen = strlen(b:buf) - for line in a:lines - let b:buflen += strlen(line) + 1 - call add(b:idxes, b:buflen) - endfor - call add(b:lines, s:EOI) " avoid 'list index out of range' error from lines[] in java_scanChar - " if b:bp >= b:buflen - " return s:EOI - " endif - - " initialize scanner - call s:scanChar() " be ready for scanning - call s:nextToken() " prime the pump -endfu - -fu! java_parser#FreeParser() - for varname in keys(s:PROTOTYPE) - exe "if exists(" . string(varname) . ") | unlet " . varname . " | endif" - endfor -endfu - -fu! java_parser#GetSnapshot() - let snapshot = {} - for varname in keys(s:PROTOTYPE) - exe "let snapshot[" . string(varname) . "] = " . varname - endfor - return snapshot -endfu - -fu! java_parser#Restore(snapshot) - for key in keys(a:snapshot) - exe "let " . key . "=" . string(a:snapshot[key]) - endfor -endfu - -" move b:bp and b:pos to the specified position -fu! java_parser#GotoPosition(pos) - let b:bp = a:pos-1 - let b:pos = a:pos - let p = java_parser#DecodePos(b:bp) - let b:line = p.line - let b:col = p.col - call s:scanChar() - call s:nextToken() -endfu - -fu! java_parser#compilationUnit() - return s:compilationUnit() -endfu - -fu! java_parser#block() - return s:block() -endfu - -fu! java_parser#statement() - return s:blockStatements() -endfu - -fu! java_parser#expression() - return s:expression() -endfu - -fu! java_parser#nextToken() - return s:nextToken() -endfu - - -" Tree {{{1 -let s:TTree = {'tag': '', 'pos': 0} " Root class for AST nodes. - -" Tree maker functions {{{2 -fu! s:ClassDef(pos, mods, ...) - return {'tag': 'CLASSDEF', 'pos': a:pos, 'mods': a:mods, 'name': ''} -endfu - -fu! s:VarDef(pos, mods, name, vartype) - return {'tag': 'VARDEF', 'pos': a:pos, 'mods': a:mods, 'name': a:name, 'vartype': a:vartype} -endfu - -fu! s:Unary(pos, opcode, arg) - return {'tag': a:opcode, 'pos': a:pos, 'arg': a:arg} -endfu - -fu! s:Binary(pos, opcode, lhs, rhs, ...) - return {'tag': a:opcode, 'pos': a:pos, 'lhs': a:lhs, 'rhs': a:rhs} -endfu - -fu! s:TypeCast(pos, clazz, expr) - return {'tag': 'TYPECAST', 'pos': a:pos, 'clazz': a:clazz, 'expr': a:expr} -endfu - -fu! s:Select(pos, selected, name) - return {'tag': 'SELECT', 'pos': a:pos, 'selected': a:selected, 'name': a:name} -endfu - -fu! s:Ident(pos, name) - return {'tag': 'IDENT', 'pos': a:pos, 'name': a:name} -endfu - -fu! s:TypeArray(pos, elementtype) - return {'tag': 'TYPEARRAY', 'pos': a:pos, 'elementtype': a:elementtype} -endfu - -fu! s:Modifiers(pos, flags, annotations) - let noFlags = s:BitAnd(a:flags, s:Flags.StandardFlags) == 0 - let mods = {'tag': 'MODIFIERS', 'flags': a:flags} - let mods.pos = noFlags && empty(a:annotations) ? -1 : a:pos - if !empty(a:annotations) - let mods.annotations = a:annotations - endif - return mods -endfu - - -" {{{2 -fu! java_parser#IsStatement(tree) - return has_key(a:tree, 'tag') && a:tree.tag =~# '^\(CLASSDEF\|VARDEF\|BLOCK\|IF\|DOLOOP\|WHILELOOP\|FORLOOP\|FOREACHLOOP\|SWITCH\|TRY\|EXEC\|LABELLED\|SYNCHRONIZED\|CASE\|BREAK\|RETURN\|SKIP\|THROW\|ASSERT\|CONTINUE\)$' -endfu - -" Tree Helper {{{1 -fu! java_parser#type2Str(type) - if type(a:type) == type("") - return a:type - endif - - let t = a:type - if t.tag == 'IDENTIFIER' - return t.value - elseif t.tag == 'IDENT' - return t.name - elseif t.tag == 'TYPEIDENT' - return t.typetag - elseif t.tag == 'SELECT' - return java_parser#type2Str(t.selected) . '.' . t.name - elseif t.tag == 'TYPEARRAY' - return java_parser#type2Str(t.elementtype) . '[]' - elseif t.tag == 'TYPEAPPLY' - return t.clazz.name - elseif t.tag == 'TEMPLATE' - let s = t.clazz.value . '<' - for arg in t.arguments - let s .= arg.value - endfor - let s .= '>' - return s - endif -endfu - -fu! s:vardef2Str(vardef) - return java_parser#type2Str(a:vardef.vartype) . ' ' . a:vardef.name -endfu - -fu! s:method2Str(methoddef) - let m = a:methoddef - let desc = m.r . ' ' . m.n . '(' - for item in m.params - let desc .= s:vardef2Str(item) . ',' - endfor - let desc = substitute(desc, ',$', '', '') - let desc .= ')' - return desc -endfu - -" Scanner {{{1 - -" nextToken() {{{2 -fu! s:nextToken() - let b:prevEndPos = b:endPos - let b:et_nextToken_count += 1 - let b:sbuf = '' - while 1 - let b:pos = b:bp - if b:ch =~ '[ \t\r\n ]' " - FF - " OAO optimized code: skip spaces - let b:col = match(b:lines[b:line], '[^ \t\r\n ]\|$', b:col) - let b:bp = b:idxes[b:line] + b:col - call s:scanChar() - let b:endPos = b:bp - continue - - elseif b:ch =~ '[a-zA-Z$_]' - " read a identifier - call s:scanIdent() - return - - elseif b:ch == '0' - call s:scanChar() - " hex - if b:ch == 'x' || b:ch == 'X' - call s:scanChar() - if b:ch == '.' - call s:scanHexFractionAndSuffix(0) - elseif s:isDigit(16) - call s:scanNumber(16) - else - call s:LexError("invalid.hex.number") - endif - " oct - else - let b:sbuf .= '0' - call s:scanNumber(8) - endif - return - - elseif b:ch =~ '[1-9]' - " read number - call s:scanNumber(10) - return - - elseif b:ch == '.' - call s:scanChar() - if b:ch =~ '[0-9]' - let b:sbuf .= '.' - call s:scanFractionAndSuffix() - " JAVA5 ELLIPSIS - elseif b:ch == '.' - let b:sbuf .= '..' - call s:scanChar() - if b:ch == '.' - call s:scanChar() - let b:sbuf .= '.' - let b:token = 'ELLIPSIS' - else - call s:LexError('malformed.fp.lit') - endif - else - let b:token = 'DOT' - endif - return - - elseif b:ch =~ '[,;(){}[\]]' - let b:token = s:keywords[b:ch] - call s:scanChar() - return - - elseif b:ch == '/' - let status = s:scanComment() - if status == 1 - continue - elseif status == 2 - return - elseif b:ch == '=' - let b:name = '/=' - let b:token = 'SLASHEQ' - call s:scanChar() - else - let b:name = '/' - let b:token = 'SLASH' - endif - return - - - elseif b:ch == "'" - call s:scanSingleQuote() - return - - elseif b:ch == '"' - call s:scanDoubleQuote() - return - - else - if s:IsSpecial(b:ch) - call s:scanOperator() - elseif b:ch =~ '[a-zA-Z_]' - call s:scanIdent() - elseif b:bp >= b:buflen - let b:token = 'EOF' - else - call s:LexError("illegal.char '" . b:ch . "'") - call s:scanChar() - endif - return - endif - endwhile -endfu - -" scanChar() Read next character. {{{2 -" one buf version -"fu! s:scanChar() -" let b:bp += 1 -" if b:bp % 256 == 0 -" let b:buf2 = strpart(b:buf, b:bp, 256) -" endif -" let b:ch = b:buf2[b:bp % 256] -"" let b:ch = b:buf[b:bp] " it will be extremely slow when buf is large -" "call s:Trace( "'" . b:ch . "'" ) -" -" if b:ch == "\r" -" let b:line += 1 -" let b:col = 0 -" elseif b:ch == "\n" -" if b:bp == 0 || b:buf[b:bp-1] == "\r" -" let b:line += 1 -" let b:col = 0 -" endif -" else -" let b:col += 1 -" endif -"endfu - -" Read next character. multiple lines version -fu! s:scanChar() - let b:bp+=1 - let b:ch=b:lines[b:line][b:col] - let b:col+=1 - if b:ch=='' - let b:ch="\r" - let b:line+=1 - let b:col=0 - endif - - if b:ch == '\' - call s:convertUnicode() - endif -endfu - -fu! java_parser#CharAt(line, col) - let ch=b:lines[a:line][a:col] - if ch == '' - let ch = "\r" - endif - return ch -endfu - -fu! s:convertUnicode() - if b:ch == '\' && b:unicodeConversionBp != b:bp - "if java_parser#CharAt(b:bp+1) == 'u' - "call s:scanChar() - "endif - endif -endfu - -" putChar() is substituted with -" let b:sbuf .= '.' - -" scanIdent() {{{2 -" OAO optimized code -fu! s:scanIdent() - let col_old = b:col - let b:col = match(b:lines[b:line], '[^a-zA-Z0-9$_]\|$', b:col) - let b:name = strpart(b:lines[b:line], col_old-1, b:col-col_old+1) - let b:token = get(s:keywords, b:name, 'IDENTIFIER') - call s:Debug('name: "' . b:name . '" of token type ' . b:token ) - let b:bp = b:idxes[b:line] + b:col - call s:scanChar() -endfu - -" Standard implementation -fu! s:scanIdent_old() - " do ... while () - let b:sbuf .= b:ch - call s:scanChar() - if b:ch !~ '[a-zA-Z0-9$_]' || b:bp >= b:buflen - let b:name = b:sbuf - let b:token = has_key(s:keywords, b:name) ? s:keywords[b:name] : 'IDENTIFIER' - call s:Debug('name: "' . b:name . '" of token type ' . b:token ) - return - endif - - while (1) - let b:sbuf .= b:ch - call s:scanChar() - if b:ch !~ '[a-zA-Z0-9$_]' || b:bp >= b:buflen - let b:name = b:sbuf - let b:token = has_key(s:keywords, b:name) ? s:keywords[b:name] : 'IDENTIFIER' - call s:Debug('name: "' . b:name . '" of token type ' . b:token ) - break - endif - endwhile -endfu - -" digit() {{{2 -" Convert an ASCII digit from its base (8, 10, or 16) to its value. -" NOTE: This only implement isdigit() check -fu! s:digit(base) - let c = b:ch - "let result = -endfu - -fu! s:isDigit(base) - if a:base == 8 - return b:ch =~ '[0-7]' - elseif a:base == 16 - return b:ch =~ '[0-9a-fA-F]' - elseif a:base == 10 - return b:ch =~ '[0-9]' - endif -endfu - -" scanNumber() {{{2 -fu! s:scanNumber(radix) - let b:radix = a:radix - let digitRadix = a:radix <= 10 ? 10 : 16 - let seendigit = 0 - while s:isDigit(a:radix) - let seendigit = 1 - let b:sbuf .= b:ch - call s:scanChar() - endwhile - if a:radix == 16 && b:ch == '.' - call s:scanHexFractionAndSuffix(seendigit) - elseif seendigit && a:radix == 16 && (b:ch == 'p' || b:ch == 'P') - call s:scanHexExponentAndSuffix() - elseif a:radix <= 10 && b:ch == '.' - let b:sbuf .= b:ch - call s:scanChar() - call s:scanFractionAndSuffix() - elseif a:radix <= 10 && b:ch =~ '[eEfFdD]' - call s:scanFractionAndSuffix() - else - if b:ch == 'l' || b:ch == 'L' - call s:scanChar() - let b:token = 'LONGLITERAL' - else - let b:token = 'INTLITERAL' - endif - endif -endfu - -fu! s:scanHexExponentAndSuffix() - if b:ch == 'p' || b:ch == 'P' - let b:sbuf .= b:ch - call s:scanChar() - if b:ch == '+' || b:ch == '-' - let b:sbuf .= b:ch - call s:scanChar() - endif - - if '0' <= b:ch && b:ch <= '9' - let b:sbuf .= b:ch - call s:scanChar() - while '0' <= b:ch && b:ch <= '9' - let b:sbuf .= b:ch - call s:scanChar() - endwhile - - "if !b:allowHexFloats - "elseif !b:hexFloatsWork - " call s:LexError("unsupported.cross.fp.lit") - "endif - else - call s:LexError("malformed.fp.lit") - endif - else - call s:LexError("malformed.fp.lit") - endif - - if b:ch == 'f' || b:ch == 'F' - let b:sbuf .= b:ch - call s:scanChar() - let b:token = 'FLOATLITERAL' - else - if b:ch == 'f' || b:ch == 'F' - let b:sbuf .= b:ch - call s:scanChar() - endif - let b:token = 'DOUBLELITERAL' - endif -endfu - -fu! s:scanFraction() - " scan fraction - while b:ch =~ '[0-9]' - let b:sbuf .= b:ch - call s:scanChar() - endwhile - - " floating point number - if b:ch == 'e' || b:ch == 'E' - let b:sbuf .= b:ch - call s:scanChar() - - if b:ch == '+' || b:ch == '-' - let b:sbuf .= b:ch - call s:scanChar() - endif - - if b:ch =~ '[0-9]' - let b:sbuf .= b:ch - call s:scanChar() - while b:ch =~ '[0-9]' - let b:sbuf .= b:ch - call s:scanChar() - endwhile - return - endif - - call s:LexError("malformed.fp.lit") - endif -endfu - -" Read fractional part and 'd' or 'f' suffix of floating point number. -fu! s:scanFractionAndSuffix() - call s:scanFraction() - if b:ch == 'f' || b:ch == 'F' - let b:sbuf .= b:ch - call s:scanChar() - let b:token = 'FLOATLITERAL' - else - if b:ch == 'd' || b:ch == 'D' - let b:sbuf .= b:ch - call s:scanChar() - endif - let b:token = 'DOUBLELITERAL' - endif -endfu - -fu! s:scanHexFractionAndSuffix(seendigit) - let seendigit = a:seendigit - let b:radix = 16 - if b:ch != '.' | echoerr "b:ch != '.'" | endif - - let b:sbuf .= b:ch - call s:scanChar() - while s:isDigit(16) - let seendigit = 1 - let b:sbuf .= b:ch - call s:scanChar() - endwhile - - if !seendigit - call s:LexError("invalid.hex.number") - else - call s:scanHexExponentAndSuffix() - endif -endfu - -" scanLitChar() {{{2 -fu! s:scanLitChar() - if b:ch == '\' - call s:scanChar() - if b:ch =~ '[0-7]' - let leadch = b:ch - let oct = b:ch - call s:scanChar() - if b:ch =~ '[0-7]' - let oct = oct * 8 + b:ch - call s:scanChar() - if leadch <= '3' && '0' <= b:ch && b:ch <= '7' - let oct = oct * 8 + b:ch - call s:scanChar() - endif - endif - let b:sbuf .= oct - - elseif b:ch == "'" || b:ch =~ '[btnfr"\\]' - let b:sbuf .= b:ch - call s:scanChar() - - " unicode escape - elseif b:ch == 'u' - while b:ch =~ '[a-zA-Z0-9]' - call s:scanChar() - endwhile - - else - call s:LexError("illegal.esc.char") - endif - - elseif b:bp < b:buflen - let b:sbuf .= b:ch - call s:scanChar() - endif -endfu - -" scanOperator() {{{2 -fu! s:scanOperator() - while 1 - if !has_key(s:keywords, b:sbuf . b:ch) - break - endif - - let b:sbuf .= b:ch - let b:token = get(s:keywords, b:sbuf, 'IDENTIFIER') - call s:Debug('sbuf: "' . b:sbuf . '" of token type ' . b:token ) - call s:scanChar() - if !s:IsSpecial(b:ch) - break - endif - endwhile -endfu - -" NOTE: add @ for JAVA5 -fu! s:IsSpecial(ch) - return a:ch =~ '[!%&*?+-:<=>^|~@]' -endfu - -" scan comment {{{2 -" return 0 - not comment, 1 - succeeded to scan comment, 2 - unclosed comment -fu! s:scanComment() - call s:scanChar() - " line comment - if b:ch == '/' - let b:token = 'LINECOMMENT' - call s:Info('line comment') - call s:SkipLineComment() - let b:endPos = b:bp - return 1 - - " classic comment - " test cases: /**/, /***/, /*******/, /*** astatement; /***/, /*/ - elseif b:ch == '*' - let b:token = 'BLOCKCOMMENT' - call s:Info('block comment') - call s:scanChar() - let time = reltime() - " javadoc - if b:ch == '*' - let b:docComment = s:scanDocComment() - " normal comment - else - call s:skipComment() - endif - let b:et_perf .= "\r" . 'comment ' . reltimestr(reltime(time)) - - if b:ch == '/' - call s:Info('end block comment') - call s:scanChar() - let b:endPos = b:bp - return 1 - else - call s:LexError('unclosed.comment') - return 2 - endif - endif - return 0 -endfu - -fu! s:SkipLineComment() - " OAO optimized code - let b:ch = "\r" - let b:line += 1 - let b:col = 0 - let b:bp = b:idxes[b:line] + b:col - - " OLD - "call s:scanChar() - "while (b:ch != "\r") - " call s:scanChar() - "endwhile -endfu - -fu! s:skipComment() - if b:ch == '*' - call s:scanChar() - if b:ch == '/' - return - else " NOTE: go back - let b:ch = '*' - let b:bp -= 1 - let b:col -= 1 - endif - endif - - " OAO optimized code - if s:Stridx('*/') > -1 - call s:scanChar() - endif - -" " Standard implementation -" while b:bp < b:buflen -" if b:ch == '*' -" call s:scanChar() -" if b:ch == '/' -" break -" endif -" else -" call s:scanChar() -" endif -" endwhile -endfu - -fu! s:scanDocComment() - call s:Info('It is javadoc') - return s:skipComment() - - " skip star '*' - while (b:bp < b:buflen && b:ch == '*') - call s:scanChar() - endwhile - - if b:bp < b:buflen && b:ch == '/' - return '' - endif - - let result = '' - while b:bp < b:buflen - if b:ch == '*' - call s:scanChar() - if b:ch == '/' - break - else - let result .= b:ch - endif - else - call s:scanChar() - let result .= b:ch - endif - endwhile - - return result -endfu - -" scan single quote {{{2 -fu! s:scanSingleQuote() - call s:scanChar() - if (b:ch == "'") - call s:LexError("empty.char.lit") - else - if (b:ch =~ '[\r\n]') - call s:LexError("illegal.line.end.in.char.lit") - endif - - call s:scanLitChar() - if b:ch == "'" - call s:scanChar() - let b:token = 'CHARLITERAL' - else - call s:LexError("unclosed.char.lit") - endif - endif -endfu - -" scan double quote {{{2 -" test cases: -" 'a"";' -" 'a"b,c";' -" 'a"b,\"c";' -" 'a"b,\\"c";' -" 'a"b,\\\"c";' -" 'a"b,\\\\"c";' -" 'a"b,\\\"c;' " NOTE: cannot handle -fu! s:scanDoubleQuote() - if match(b:lines[b:line], '\\"', b:col) == -1 - let idx = matchend(b:lines[b:line], '\(\\\(["\\''ntbrf]\)\|[^"]\)*"', b:col) - if idx != -1 - let b:sbuf = strpart(b:lines[b:line], b:col, idx-b:col-1) - let b:col = idx-1 " back to the end - let b:bp = b:idxes[b:line] + b:col - call s:scanChar() - let b:token = 'STRINGLITERAL' - else - call s:LexError("unclosed.str.lit") - endif - call s:scanChar() - return - endif - - - call s:scanChar() - while b:ch !~ '["\r\n]' && b:bp < b:buflen - call s:scanLitChar() - endwhile - - if b:ch == '"' - let b:token = 'STRINGLITERAL' - call s:scanChar() - else - call s:LexError("unclosed.str.lit") - endif -endfu - -" lex errors {{{2 -fu! s:LexError(key, ...) - let pos = a:0 == 0 ? b:pos : a:1 - let b:token = 'ERROR' - let b:errPos = pos - call s:Log(4, b:pos, '[lex error]:' . s:Pos2Str(pos) . ': ' . a:key) -endfu - -" Scanner Helper {{{1 -" gotoMatchEnd {{{2 -fu! s:gotoMatchEnd(one, another, ...) - while b:bp < b:buflen - if b:ch == a:another - call s:scanChar() - if has_key(s:keywords, a:another) - let b:token = s:keywords[a:another] - else - echoerr '' - endif - break - - elseif b:ch == a:one - call s:scanChar() - call s:gotoMatchEnd(a:one, a:another) - - " skip commment - elseif b:ch == '/' - call s:scanComment() - - " skip literal character - elseif b:ch == "'" - call s:scanSingleQuote() - - " skip literal string - elseif b:ch == '"' - call s:scanDoubleQuote() - - else - " OAO - call s:Match('[' . a:one . a:another . '/"'']') - " OLD - "call s:scanChar() - endif - endwhile - - " For such situation: after accept one token, the next token is just the same. - let nextTokenIsLBRACE = a:0 == 0 ? 0 : a:1 - if nextTokenIsLBRACE - call s:gotoMatchEnd(a:one, a:another) - endif - - return b:bp -endfu - -" gotoSemi {{{2 -fu! s:gotoSemi() - while b:bp < b:buflen - if b:ch == ';' - let b:pos = b:bp - call s:scanChar() - let b:token = 'SEMI' - return - - " skip commment - elseif b:ch == '/' - call s:scanComment() - - " skip literal character - elseif b:ch == "'" - call s:scanSingleQuote() - - " skip literal string - elseif b:ch == '"' - call s:scanDoubleQuote() - - elseif b:ch == '{' - call s:scanChar() - call s:gotoMatchEnd('{', '}') - - elseif b:ch == '(' - call s:scanChar() - call s:gotoMatchEnd('(', ')') - - elseif b:ch == '[' - call s:scanChar() - call s:gotoMatchEnd('[', ']') - - else - " OAO - call s:Match('[;({[/"'']') - " OLD - "call s:scanChar() - endif - endwhile -endfu - -" s:Strpart(), s:Stridx(), s:Match() {{{2 -fu! Strpart(start, len) - let startline = java_parser#DecodePos(a:start).line - let endline = java_parser#DecodePos(a:start + a:len).line - let str = join(b:lines[startline:endline-1]) . b:lines[endline] - return strpart(str, a:start-b:idxes[startline], a:len) -endfu - -fu! s:Stridx(needle) - let found = 0 - while b:line < len(b:lines)-1 - let idx = stridx(b:lines[b:line], a:needle, b:col) - if idx > -1 - let found = 1 - let b:col = idx - break - endif - let b:line += 1 - let b:col = 0 - endwhile - - if found - let b:bp = b:idxes[b:line] + b:col - call s:scanChar() - return b:bp - else - let b:bp = b:buflen - let b:ch = s:EOI - return -1 - endif -endfu - -fu! s:Match(pat) - let bp_old = b:bp - let line_old = b:line - let col_old = b:col - - let found = 0 - while b:line < len(b:lines)-1 - let idx = match(b:lines[b:line], a:pat, b:col) - if idx > -1 - let found = 1 - let b:col = idx - break - endif - let b:line += 1 - let b:col = 0 - endwhile - - if found - let b:bp = b:idxes[b:line] + b:col-1 - call s:scanChar() - return b:bp - else - let b:bp = bp_old - let b:line = line_old - let b:col = col_old - call s:scanChar() - return -1 - endif -endfu - - -" conversion between position and (line, col) {{{2 -fu! java_parser#MakePos(line, col) - return b:idxes[a:line] + a:col -endfu - -fu! java_parser#DecodePos(pos) - let line = -1 - for idx in b:idxes - if idx > a:pos - break - endif - let line += 1 - endfor - let col = a:pos - b:idxes[line] - return {'line': line, 'col': col} -endfu - -fu! s:Pos2Str(pos) - let o = java_parser#DecodePos(a:pos) - return '(' . (o.line+1) . ',' . (o.col+1) . ')' -endfu - -" Bitwise operator emulators {{{1 -" NOTE: For more than 32 bit number, use the string bits form. - -" bit operator ~ -fu! s:BitNot(v) - return s:Bits2Number( s:BitNot_binary(s:Number2Bits(a:v)) ) -endfu - -fu! s:BitNot_binary(v) - let v = substitute(a:v, '^0*\([01]\+\)', '\1', 'g') - let v = substitute(v, '1', '2', 'g') - let v = substitute(v, '0', '1', 'g') - let v = substitute(v, '2', '0', 'g') - return v -endfu - -" bit operator & -fu! s:BitAnd(n1, n2) - if a:n1 == 0 || a:n2 == 0 | return 0 | endif - if a:n1 == a:n2 | return 1 | endif - return s:Bits2Number( s:BitOperator_binary(s:Number2Bits(a:n1), s:Number2Bits(a:n2), 'n1[i] == "1" && n2[i] == "1"') ) -endfu - -" bit operator | -fu! s:BitOr(n1, n2, ...) - if a:0 == 0 - if a:n1 == 0 - return a:n2 - elseif a:n2 == 0 - return a:n1 - endif - endif - let result = s:BitOperator_binary(s:Number2Bits(a:n1), s:Number2Bits(a:n2), 'n1[i] == "1" || n2[i] == "1"') - for a in a:000 - let result = s:BitOperator_binary(result, s:Number2Bits(a), 'n1[i] == "1" || n2[i] == "1"') - endfor - return s:Bits2Number( result ) -endfu - -" bit operator ^ -fu! s:BitXor(n1, n2) - if a:n1 == a:n2 | return 0 | endif - return s:Bits2Number( s:BitOperator_binary(s:Number2Bits(a:n1), s:Number2Bits(a:n2), 'n1[i] != n2[i]') ) -endfu - -fu! s:BitOperator_binary(n1, n2, comparator) - let n1 = a:n1 - let n2 = a:n2 - - let len1 = len(n1) - let len2 = len(n2) - let len = len1 - if len1 > len2 - let n2 = repeat('0', len1-len2) . n2 - else - let len = len2 - let n1 = repeat('0', len2-len1) . n1 - endif - - let i = 0 - let bits = '' - while i < len - let bits .= eval(a:comparator) ? '1' : '0' - let i += 1 - endwhile - return bits -endfu - -" bit operator << -fu! s:BitMoveLeft() -endfu - -" bit operator >> -fu! s:BitMoveRight() -endfu - -" helper function: convert a number to a string consisted of '0' or '1' indicating number -fu! s:Number2Bits(n, ...) - if type(a:n) == type("") | return a:n | endif - if a:n == 0 | return '0' | endif - - let n = a:n - let bits = '' - while n != 0 - let bit = n % 2 - "echo 'n: ' . n . ' bit: ' . bit - let bits = bit . bits - let n = (n-bit)/ 2 - endwhile - if a:0 > 0 - let bits = repeat(a:1 - len(bits)) . bits - endif - return bits -endfu - -" helper function: convert a string consisted of '0' or '1' indicating number to a number -" precondition: bits must not be empty string -fu! s:Bits2Number(bits) - let len = len(a:bits) - let n = a:bits[0] - let i = 1 - while i < len - let n = n * 2 + a:bits[i] - let i += 1 - endwhile - return n -endfu - - -let s:modifier_keywords = ['strictfp', 'abstract', 'interface', 'native', 'transient', 'volatile', 'synchronized', 'final', 'static', 'protected', 'private', 'public'] -fu! s:String2Flags(str) - let mod = [0,0,0,0,0,0,0,0,0,0,0,0,] - for item in split(a:str, '\s\+') - if index(s:modifier_keywords, item) != -1 - let mod[index(s:modifier_keywords, item)] = '1' - endif - endfor - return join(mod[index(mod, '1'):], '') -endfu - -" Log utilities {{{1 -" level -" 5 off/fatal -" 4 error -" 3 warn -" 2 info -" 1 debug -" 0 trace -fu! java_parser#SetLogLevel(level) - let b:loglevel = a:level -endfu - -fu! java_parser#GetLogLevel() - return exists('b:loglevel') ? b:loglevel : 3 -endfu - -fu! java_parser#GetLogContent() - return b:log -endfu - -fu! s:Trace(msg) - call s:Log(0, b:pos, a:msg) -endfu - -fu! s:Debug(msg) - call s:Log(1, b:pos, a:msg) -endfu - -fu! s:Info(msg) - call s:Log(2, b:pos, a:msg) -endfu - -fu! s:Log(level, pos, key, ...) - if a:level >= java_parser#GetLogLevel() - echo a:key - call add(b:log, a:key) - endif -endfu - -fu! s:ShowWatch(...) - let at = a:0 > 0 ? a:1 : '' - echo '-- b:bp ' . b:bp . string(java_parser#DecodePos(b:bp)) . ' b:ch "' . b:ch . '" b:name ' . b:name . ' b:token ' . b:token . ' b:pos ' .b:pos . ' endPos ' . b:endPos . ' prevEndPos ' . b:prevEndPos . ' errPos ' . b:errPos . ' errorEndPos ' . b:errorEndPos . at -endfu - -fu! java_parser#Exe(cmd) - exe a:cmd -endfu - -" Parser {{{1 -" skip() Skip forward until a suitable stop token is found. {{{2 -fu! s:skip(stopAtImport, stopAtMemberDecl, stopAtIdentifier, stopAtStatement) - while 1 - if b:token == 'SEMI' - call s:nextToken() - return - elseif b:token =~# '^\(PUBLIC\|FINAL\|ABSTRACT\|MONKEYS_AT\|EOF\|CLASS\|INTERFACE\|ENUM\)$' - return - elseif b:token == 'IMPORT' - if a:stopAtImport - return - endif - elseif b:token =~# '^\(LBRACE\|RBRACE\|PRIVATE\|PROTECTED\|STATIC\|TRANSIENT\|NATIVE\|VOLATILE\|SYNCHRONIZED\|STRICTFP\|LT\|BYTE\|SHORT\|CHAR\|INT\|LONG\|FLOAT\|DOUBLE\|BOOLEAN\|VOID\)$' - if a:stopAtMemberDecl - return - endif - elseif b:token == 'IDENTIFIER' - if a:stopAtIdentifier - return - endif - elseif b:token =~# '^\(CASE\|DEFAULT\|IF\|FOR\|WHILE\|DO\|TRY\|SWITCH\|RETURN\|THROW\|BREAK\|CONTINUE\|ELSE\|FINALLY\|CATCH\)$' - if a:stopAtStatement - return - endif - endif - call s:nextToken() - endwhile -endfu - -" syntax errors {{{2 -fu! s:SyntaxError(key, ...) - let pos = a:0 == 0 ? b:pos : a:1 - let errs = a:0 > 1 ? a:2 : [] - call s:setErrorEndPos(pos) - call s:ReportSyntaxError(pos, a:key) - return {'tag': 'ERRONEOUS', 'pos': pos, 'errs': errs} -endfu - -fu! s:ReportSyntaxError(pos, key, ...) - if a:pos > b:errPos || a:pos == -1 - let key = a:key . (b:token == 'EOF' ? ' and premature.eof' : '') - call s:Log(4, a:pos, '[syntax error]' . s:Pos2Str(a:pos) . ': ' . key) - endif - let b:errPos = a:pos -endfu - -" accept() {{{2 -fu! s:accept(token_type) - "call s:Debug(b:token . ' == ' . a:token_type . (b:token == a:token_type)) - if b:token == a:token_type - call s:nextToken() - else - call s:setErrorEndPos(b:pos) - call s:ReportSyntaxError(b:prevEndPos, s:token2string(a:token_type) . " expected") - "call s:nextToken() - endif -endfu - -fu! s:token2string(token) - if a:token =~# '^\(DOT\|COMMA\|SEMI\|LPAREN\|RPAREN\|LBRACKET\|RBRACKET\|LBRACE\|RBRACE\)$' - return "'" . a:token . "'" - endif - return a:token -endfu - - -" illegal() {{{2 -fu! s:illegal(...) - call s:setErrorEndPos(b:pos) - return s:SyntaxError(s:modeAndEXPR() ? 'illegal.start.of.expr' : 'illegal.start.of.type', a:0 == 0 ? b:pos : a:1) -endfu - -" setErrorEndPos() {{{2 -fu! s:setErrorEndPos(errPos) - if a:errPos > b:errorEndPos - let b:errorEndPos = a:errPos - endif -endfu - -" ident() {{{2 -" Ident = IDENTIFIER -fu! s:ident() - call s:Trace('s:ident ' . b:token) - - if b:token == 'IDENTIFIER' - let name = b:name - call s:nextToken() - return name - - elseif b:token == 'ASSERT' - if s:allowAsserts - call s:Log(4, b:pos, 'assert.as.identifier') - call s:nextToken() - return '' - else - call s:Log(3, b:pos, 'assert.as.identifier') - let name = b:name - call s:nextToken() - return name - endif - - elseif b:token == 'ENUM' - if b:allowEnums - call s:Log(4, b:pos, 'enum.as.identifier') - call s:nextToken() - return '' - else - call s:Log(3, b:pos, 'enum.as.identifier') - let name = b:name - call s:nextToken() - return name - endif - - else - call s:accept('IDENTIFIER') - return '' - endif -endfu - -" qualident() {{{2 -" Qualident = Ident { DOT Ident } -fu! s:qualident() - let t = s:Ident(b:pos, s:ident()) - while b:token == 'DOT' - let pos = b:pos - call s:nextToken() - let t = s:Select(b:pos, t, s:ident()) - "let t.name .= '.' . s:ident() " FIXME - endwhile - return t -endfu - -" literal() {{{2 -" Literal = INTLITERAL | LONGLITERAL | FLOATLITERAL | DOUBLELITERAL | CHARLITERAL | STRINGLITERAL | TRUE | FALSE | NULL -fu! s:literal(prefix) - let t = {'tag': 'LITERAL', 'pos': b:pos} - if b:token == 'INTLITERAL' - let t.typetag = 'INT' - let t.value = b:sbuf - elseif b:token == 'LONGLITERAL' - let t.typetag = 'LONG' - let t.value = b:sbuf - elseif b:token == 'FLOATLITERAL' - let t.typetag = 'FLOAT' - let t.value = b:sbuf - elseif b:token == 'DOUBLELITERAL' - let t.typetag = 'DOUBLE' - let t.value = b:sbuf - elseif b:token == 'CHARLITERAL' - let t.typetag = 'CHAR' - let t.value = b:sbuf - elseif b:token == 'STRINGLITERAL' - let t.typetag = 'CLASS' - let t.value = b:sbuf - elseif b:token == 'TRUE' - let t.typetag = 'BOOLEAN' - let t.value = 1 - elseif b:token == 'FALSE' - let t.typetag = 'BOOLEAN' - let t.value = 0 - elseif b:token == 'NULL' - let t.typetag = 'BOT' - let t.value = 'null' - else - echoerr 'can not reach here' - endif - call s:nextToken() - return t -endfu - -" {{{2 -" terms, expression, type {{{2 -" When terms are parsed, the mode determines which is expected: -" mode = EXPR : an expression -" mode = TYPE : a type -" mode = NOPARAMS : no parameters allowed for type -" mode = TYPEARG : type argument -let s:EXPR = 1 -let s:TYPE = 2 -let s:NOPARAMS = 4 -let s:TYPEARG = 8 -let s:EXPR_OR_TYPE = 3 -let s:EXPR_OR_TYPE_OR_NOPARAMS = 7 -let s:TYPEARG_OR_NOPARAMS = 12 - -fu! s:modeAndEXPR() - return b:mode % 2 -endfu - -fu! s:modeAndTYPE() - return s:BitAnd(b:mode, s:TYPE) -endfu - -" terms can be either expressions or types. -fu! s:expression() - return s:term(s:EXPR) -endfu - -fu! s:type() - return s:term(s:TYPE) -endfu - -fu! s:typeList() - let ts = [] - call add(ts, s:type()) - while b:token == 'COMMA' - call s:nextToken() - call add(ts, s:type()) - endwhile - return ts -endfu - -" Expression = Expression1 [ExpressionRest] -" ExpressionRest = [AssignmentOperator Expression1] -" AssignmentOperator = "=" | "+=" | "-=" | "*=" | "/=" | "&=" | "|=" | "^=" | -" "%=" | "<<=" | ">>=" | ">>>=" -" Type = Type1 -" TypeNoParams = TypeNoParams1 -" StatementExpression = Expression -" ConstantExpression = Expression -fu! s:term(...) - let prevmode = b:mode - let b:mode = a:0 == 0 ? b:mode : a:1 - - let t = s:term1() - if s:modeAndEXPR() && b:token == 'EQ' || b:token =~# '^\(PLUSEQ\|SUBEQ\|STAREQ\|SLASHEQ\|AMPEQ\|BAREQ\|CARETEQ\|PERCENTEQ\|LTLTEQ\|GTGTEQ\|GTGTGTEQ\)$' - let t = s:termRest(t) - endif - - let b:lastmode = b:mode - let b:mode = prevmode - return t -endfu - -fu! s:termRest(t) - if b:token == 'EQ' - let pos = b:pos - call s:nextToken() - let b:mode = s:EXPR - return {'tag': 'ASSIGN', 'pos': pos, 'lhs': a:t, 'rhs': s:term()} - - elseif b:token =~# '^\(PLUSEQ\|SUBEQ\|STAREQ\|SLASHEQ\|PERCENTEQ\|AMPEQ\|BAREQ\|CARETEQ\|LTLTEQ\|GTGTEQ\|GTGTGTEQ\)$' - let pos = b:pos - let token = b:token - call s:nextToken() - let b:mode = s:EXPR - return {'tag': s:optag(token), 'pos': pos, 'lhs': a:t, 'rhs': s:term()} - - else - return a:t - endif -endfu - -" Expression1 = Expression2 [Expression1Rest] -" Type1 = Type2 -" TypeNoParams1 = TypeNoParams2 -fu! s:term1() - let t = s:term2() - if s:modeAndEXPR() && b:token == 'QUES' - let b:mode = s:EXPR - return s:term1Rest(t) - else - return t - endif -endfu - -" Expression1Rest = ["?" Expression ":" Expression1] -fu! s:term1Rest(t) - if b:token == 'QUES' - let t = {'tag': 'CONDEXPR', 'pos': b:pos, 'cond': a:t} - call s:nextToken() - let t.truepart = s:term() - call s:accept('COLON') - let t.falsepart = s:term1() - return t - else - return a:t - endif -endfu - -" Expression2 = Expression3 [Expression2Rest] -" Type2 = Type3 -" TypeNoParams2 = TypeNoParams3 -fu! s:term2() - let t = s:term3() - if s:modeAndEXPR() && s:prec(b:token) >= s:opprecedences.orPrec - let b:mode = s:EXPR - return s:term2Rest(t, s:opprecedences.orPrec) - else - return t - endif -endfu - -" Expression2Rest = {infixop Expression3} -"" | Expression3 instanceof Type -" infixop = "||" -" | "&&" -" | "|" -" | "^" -" | "&" -" | "==" | "!=" -" | "<" | ">" | "<=" | ">=" -" | "<<" | ">>" | ">>>" -" | "+" | "-" -" | "*" | "/" | "%" -fu! s:term2Rest(t, minprec) - let odStack = [a:t] " for expressions - let opStack = [] " for tokens - let top = 0 - let startPos = b:pos - let topOp = 'ERROR' - while s:prec(b:token) >= a:minprec - call add(opStack, topOp) - let top += 1 - let topOp = b:token - let pos = b:pos - call s:nextToken() - call add(odStack, topOp == 'INSTANCEOF' ? s:type() : s:term3()) - while top > 0 && s:prec(topOp) >= s:prec(b:token) - let odStack[top-1] = s:makeOp(pos, topOp, odStack[top-1], odStack[top]) - let top -= 1 - let topOp = opStack[top] - endwhile - endwhile - "assert top == 0 - let t = odStack[0] - - if t.tag == 'PLUS' - let buf = s:foldStrings(t) - if buf != '' - let t = {'tag': 'LITERAL', 'pos': startPos, 'typetag': 'CLASS', 'value': t} - endif - endif - return t -endfu - -fu! s:makeOp(pos, topOp, od1, od2) - if a:topOp == 'INSTANCEOF' - return {'tag': 'TYPETEST', 'pos': a:pos, 'expr': a:od1, 'clazz': a:od2} - else - return s:Binary(a:pos, s:optag(a:topOp), a:od1, a:od2) - endif -endfu - -fu! s:foldStrings(tree) - let tree = a:tree - let buf = '' - while 1 - if tree.tag == 'LITERAL' - let lit = tree - if lit.typetag == 'CLASS' - let sbuf = lit.value - if buf != '' - let sbuf .= buf - endif - return sbuf - endif - elseif tree.tag == 'PLUS' - let op = tree - if op.rhs.tag == 'LITERAL' - let lit = op.rhs - if lit.typetag == 'CLASS' - let buf = lit.value . buf - let tree = op.lhs - continue - endif - endif - endif - return '' - endwhile -endfu - -" Expression3 = PrefixOp Expression3 {{{2 -" | "(" Expr | TypeNoParams ")" Expression3 -" | Primary {Selector} {PostfixOp} -" Primary = "(" Expression ")" -" | Literal -" | [TypeArguments] THIS [Arguments] -" | [TypeArguments] SUPER SuperSuffix -" | NEW [TypeArguments] Creator -" | Ident { "." Ident } -" [ "[" ( "]" BracketsOpt "." CLASS | Expression "]" ) -" | Arguments -" | "." ( CLASS | THIS | [TypeArguments] SUPER Arguments | NEW [TypeArguments] InnerCreator ) -" ] -" | BasicType BracketsOpt "." CLASS -" PrefixOp = "++" | "--" | "!" | "~" | "+" | "-" -" PostfixOp = "++" | "--" -" Type3 = Ident { "." Ident } [TypeArguments] {TypeSelector} BracketsOpt -" | BasicType -" TypeNoParams3 = Ident { "." Ident } BracketsOpt -" Selector = "." [TypeArguments] Ident [Arguments] -" | "." THIS -" | "." [TypeArguments] SUPER SuperSuffix -" | "." NEW [TypeArguments] InnerCreator -" | "[" Expression "]" -" TypeSelector = "." Ident [TypeArguments] -" SuperSuffix = Arguments | "." Ident [Arguments] -" NOTE: We need only type expression. -fu! s:term3() - let pos = b:pos - let t = copy(s:TTree) - - call s:Debug('term3() b:token is ' . b:token) - let typeArgs = s:typeArgumentsOpt(s:EXPR) - - if b:token == 'QUES' - if s:modeAndTYPE() && s:BitAnd(b:mode, s:TYPEARG_OR_NOPARAMS) == s:TYPEARG - let b:mode = s:TYPE - return s:typeArgument() - else - return s:illegal() - endif - - elseif b:token =~# '^\(PLUSPLUS\|SUBSUB\|BANG\|TILDE\|PLUS\|SUB\)$' - if typeArgs == [] && s:modeAndEXPR() - let token = b:token - call s:nextToken() - let b:mode = s:EXPR - if token == 'SUB' && (b:token == 'INTLITERAL' || b:token == 'LONGLITERAL') && b:radix == 10 - let b:mode = s:EXPR - let t = s:literal('-') - else - let t = s:term3() - return s:Unary(pos, s:unoptag(token), t) - endif - else - return s:illegal() - endif - - elseif b:token == 'LPAREN' - if typeArgs == [] && s:modeAndEXPR() - call s:nextToken() - let b:mode = s:EXPR_OR_TYPE_OR_NOPARAMS - let t = s:term3() - if s:modeAndEXPR() && b:token == 'LT' - let op = 'LT' - let pos1 = b:pos - call s:nextToken() - let b:mode = s:BitAnd(b:mode, s:EXPR_OR_TYPE) - let b:mode = s:BitOr(b:mode, s:TYPEARG) - let t1 = s:term3() - if s:modeAndTYPE() && (b:token == 'COMMA' || b:token == 'GT') - let b:mode = s:TYPE - let args = [] - call add(args, t1) - while b:token == 'COMMA' - call s:nextToken() - call add(args, s:typeArgument()) - endwhile - call s:accept('GT') - let t = {'tag': 'TYPEAPPLY', 'pos': pos1, 'clazz': t, 'arguments': args} - " checkGenerics - let t = s:bracketsOpt(t) - elseif s:modeAndEXPR() - let b:mode = s:EXPR - let t = s:Binary(pos1, op, t, s:term2Rest(t1, s:opprecedences.shiftPrec)) - let t = s:termRest(s:term1Rest(s:term2Rest(t, s:opprecedences.orPrec))) - else - call s:accept('GT') - endif - else - let t = s:termRest(s:term1Rest(s:term2Rest(t, s:opprecedences.orPrec))) - endif - call s:accept('RPAREN') - let b:lastmode = b:mode - let b:mode = s:EXPR - if s:BitAnd(b:lastmode, s:EXPR) == 0 - return s:TypeCast(pos, t, s:term3()) - elseif s:BitAnd(b:lastmode, s:TYPE) != 0 - if b:token =~# '^\(BANG\|TILDE\|LPAREN\|THIS\|SUPER\|INTLITERAL\|LONGLITERAL\|FLOATLITERAL\|DOUBLELITERAL\|CHARLITERAL\|STRINGLITERAL\|TRUE\|FALSE\|NULL\|NEW\|IDENTIFIER\|ASSERT\|ENUM\|BYTE\|SHORT\|CHAR\|INT\|LONG\|FLOAT\|DOUBLE\|BOOLEAN\|VOID\)$' - return s:TypeCast(pos, t, s:term3()) - endif - endif - else - return s:illegal() - endif - let t = {'tag': 'PARENS', 'pos': pos, 'expr': t} - - elseif b:token == 'THIS' - if s:modeAndEXPR() - let b:mode = s:EXPR - let t = s:Ident(pos, 'this') - call s:nextToken() - if typeArgs == [] - let t = s:argumentsOpt([], t) - else - let t = s:arguments(typeArgs, t) - endif - let typeArgs = [] - else - return s:illegal() - endif - - elseif b:token == 'SUPER' - if s:modeAndEXPR() - let b:mode = s:EXPR - let t = s:superSuffix(typeArgs, s:Ident(pos, 'super')) - let typeArgs = [] - else - return s:illegal() - endif - - elseif b:token =~# '^\(INTLITERAL\|LONGLITERAL\|FLOATLITERAL\|DOUBLELITERAL\|CHARLITERAL\|STRINGLITERAL\|TRUE\|FALSE\|NULL\)$' - if typeArgs == [] && s:modeAndEXPR() - let b:mode = s:EXPR - let t = s:literal('') - else - return s:illegal() - endif - - elseif b:token == 'NEW' - if typeArgs != [] - return s:illegal() - endif - - if s:modeAndEXPR() - let b:mode = s:EXPR - call s:nextToken() - if b:token == 'LT' - let typeArgs = s:typeArguments() - endif - let t = s:creator(pos, typeArgs) - let typeArgs = [] - else - return s:illegal() - endif - - elseif b:token =~# '^\(IDENTIFIER\|ASSERT\|ENUM\)$' - if typeArgs != [] - return s:illegal() - endif - - let t = s:Ident(pos, s:ident()) - while 1 - if b:token == 'LBRACKET' - "let t.value = '[' " FIXME - call s:nextToken() - if b:token == 'RBRACKET' - "let t.value .= ']' - call s:nextToken() - let t = s:bracketsSuffix(s:TypeArray(pos, s:bracketsOpt(t))) - else - if s:modeAndEXPR() - let b:mode = s:EXPR - let t = {'tag': 'INDEXED', 'pos': pos, 'indexed': t, 'index': s:term()} - endif - call s:accept('RBRACKET') - "let t.value .= ']' - endif - break - - elseif b:token == 'LPAREN' - if s:modeAndEXPR() - let b:mode = s:EXPR - let t = s:arguments(typeArgs, t) - let typeArgs = [] - "call s:accept('LPAREN') - "call s:gotoMatchEnd('(', ')', b:token == 'LPAREN') - "call s:accept('RPAREN') - endif - break - - elseif b:token == 'DOT' - call s:nextToken() - let typeArgs = s:typeArgumentsOpt(s:EXPR) - if s:modeAndEXPR() - if b:token == 'CLASS' || b:token == 'THIS' - if typeArgs != [] - return s:illegal() - endif - let b:mode = s:EXPR - let t = s:Select(pos, t, b:token == 'CLASS' ? 'class' : 'this') - call s:nextToken() - break - elseif b:token == 'SUPER' - let b:mode = s:EXPR - let t = s:Select(pos, t, 'super') - let t = s:superSuffix(typeArgs, t) - let typeArgs = [] - break - elseif b:token == 'NEW' - if typeArgs != [] - return s:illegal() - endif - let b:mode = s:EXPR - let pos1 = b:pos - call s:nextToken() - if b:token == 'LT' - let typeArgs = s:typeArguments() - endif - let t = s:innerCreator(pos1, typeArgs, t) - let typeArgs = [] - break - endif - endif - let t = s:Select(pos, t, s:ident()) - else - break - endif - endwhile - if typeArgs != [] | call s:illegal() | endif - let t = s:typeArgumentsOpt2(t) - - elseif b:token =~# '^\(BYTE\|SHORT\|CHAR\|INT\|LONG\|FLOAT\|DOUBLE\|BOOLEAN\)$' - if typeArgs != [] | call s:illegal() | endif - let t = s:bracketsSuffix(s:bracketsOpt(s:basicType())) - - elseif b:token == 'VOID' - if typeArgs != [] | call s:illegal() | endif - if s:modeAndEXPR() - call s:nextToken() - if b:token == 'DOT' - let ti = {'tag': 'TYPEIDENT', 'pos': pos, 'typetag': 'void'} " FIXME - let t = s:bracketsSuffix(ti) - else - return s:illegal(pos) - endif - else - return s:illegal() - endif - - else - return s:illegal() - endif - - if typeArgs != [] - return s:illegal() - endif - - while 1 - let pos1 = b:pos - if b:token == 'LBRACKET' - call s:nextToken() - if s:modeAndEXPR() - let oldmode = b:mode - let b:mode = s:TYPE - if b:token == 'RBRACKET' - call s:nextToken() - let t = s:bracketsOpt(t) - let t = s:TypeArray(pos1, t) - return t - endif - let b:mode = oldmode - endif - if s:modeAndEXPR() - let b:mode = s:EXPR - let t = {'tag': 'INDEXED', 'pos': pos1, 'indexed': t, 'index': s:term()} - endif - call s:accept('RBRACKET') - - elseif b:token == 'DOT' - call s:nextToken() - let typeArgs = s:typeArgumentsOpt(s:EXPR) - if b:token == 'SUPER' && s:modeAndEXPR() - let b:mode = s:EXPR - let t = s:Select(pos1, t, 'super') - call s:nextToken() - let t = s:arguments(typeArgs, t) - let typeArgs = [] - elseif b:token == 'NEW' && s:modeAndEXPR() - if typeArgs != [] - return s:illegal() - endif - let b:mode = s:EXPR - let pos2 = b:pos - call s:nextToken() - if b:token == 'LT' - let typeArgs = s:typeArguments() - endif - let t = s:innerCreator(pos2, typeArgs, t) - let typeArgs = [] - else - let t = s:Select(pos1, t, s:ident()) - let t = s:argumentsOpt(typeArgs, s:typeArgumentsOpt2(t)) - let typeArgs = [] - endif - else - break - endif - endwhile - - - while (b:token == 'PLUSPLUS' || b:token == 'SUBSUB') && s:modeAndEXPR() - let b:mode = s:EXPR - let t = s:Unary(b:pos, b:token == 'PLUSPLUS' ? 'POSTINC' : 'POSTDEC', t) - call s:nextToken() - endwhile - return t -endfu - -fu! s:superSuffix(typeArgs, t) - let typeArgs = a:typeArgs - let t = a:t - call s:nextToken() - if b:token == 'LPAREN' || typeArgs != [] - let t = s:arguments(typeArgs, t) - else - let pos = b:pos - call s:accept('DOT') - let typeArgs = b:token == 'LT' ? s:typeArguments() : [] - let t = s:Select(pos, t, s:ident()) - let t = s:argumentsOpt(typeArgs, t) - endif - return t -endfu - -" BasicType = BYTE | SHORT | CHAR | INT | LONG | FLOAT | DOUBLE | BOOLEAN {{{2 -fu! s:basicType() - let t = {'tag': 'TYPEIDENT', 'pos': b:pos, 'typetag': s:typetag(b:token)} - call s:nextToken() - return t -endfu - -" ArgumentsOpt = [ Arguments ] {{{2 -fu! s:argumentsOpt(typeArgs, t) - if s:modeAndEXPR() && b:token == 'LPAREN' || a:typeArgs != [] - let b:mode = s:EXPR - return s:arguments(a:typeArgs, a:t) - else - return a:t - endif -endfu - -" Arguments = "(" [Expression { COMMA Expression }] ")" -fu! s:arguments(...) - let pos = b:pos - let args = [] - if b:token == 'LPAREN' - call s:nextToken() - if b:token != 'RPAREN' - call add(args, s:expression()) - while b:token == 'COMMA' - call s:nextToken() - call add(args, s:expression()) - endwhile - endif - call s:accept('RPAREN') - else - call s:SyntaxError(') expected') - endif - - if a:0 == 0 - return args - else - let typeArgs = a:1 - let t = a:2 - return {'tag': 'APPLY', 'pos': pos, 'typeargs': typeArgs, 'meth': t, 'args': args} - endif -endfu - -" typeArgument generic type {{{2 -fu! s:typeArgumentsOpt2(t) - if b:token == 'LT' && s:modeAndTYPE() && s:BitAnd(b:mode, s:NOPARAMS) == 0 - let b:mode = s:TYPE - " checkGenerics() - return s:typeArguments(a:t) - else - return a:t - endif -endfu - -fu! s:typeArgumentsOpt(...) - let useMode = a:0 == 0 ? s:TYPE : a:1 - - if b:token == 'LT' - " checkGenerics() - if s:BitAnd(b:mode, useMode) == 0 || s:BitAnd(b:mode, s:NOPARAMS) != 0 - return s:illegal() - endif - let b:mode = useMode - return s:typeArguments() - endif - return [] -endfu - -" TypeArguments = "<" TypeArgument {"," TypeArgument} ">" -fu! s:typeArguments(...) - let pos = b:pos - - let args = [] - if b:token == 'LT' - call s:nextToken() - call add(args, s:modeAndEXPR() ? s:type() : s:typeArgument()) - while b:token == 'COMMA' - call s:nextToken() - call add(args, s:modeAndEXPR() ? s:type() : s:typeArgument()) - endwhile - - if b:token == 'GTGTGTEQ' - let b:token = 'GTGTEQ' - elseif b:token == 'GTGTEQ' - let b:token = 'GTEQ' - elseif b:token == 'GTEQ' - let b:token = 'EQ' - elseif b:token == 'GTGTGT' - let b:token = 'GTGT' - elseif b:token == 'GTGT' - let b:token = 'GT' - else - call s:accept('GT') - endif - else - call s:SyntaxError("LT expected") - endif - - if a:0 == 0 - return args - else - return {'tag': 'TYPEAPPLY', 'pos': pos, 'clazz': a:1, 'arguments': args} - endif -endfu - -" TypeArgument = Type -" | "?" -" | "?" EXTENDS Type {"&" Type} -" | "?" SUPER Type -fu! s:typeArgument() - if b:token != 'QUES' - return s:type() - endif - - call s:nextToken() - if b:token == 'EXTENDS' - call s:nextToken() - return s:type() - elseif b:token == 'SUPER' - call s:nextToken() - return s:type() - elseif b:token == 'IDENTIFIER' - let id = ident() - else - endif -endfu - - -" BracketsOpt = {"[" "]"} {{{2 -fu! s:bracketsOpt(t) - let t = a:t - while b:token == 'LBRACKET' - let pos = b:pos - call s:nextToken() - let t = s:bracketsOptCont(t, pos) - endwhile - return t -endfu - -fu! s:bracketsOptCont(t, pos) - let t = a:t - call s:accept('RBRACKET') - let t = s:bracketsOpt(t) - return s:TypeArray(a:pos, t) -endfu - -" BracketsSuffixExpr = "." CLASS -" BracketsSuffixType = -fu! s:bracketsSuffix(t) - let t = a:t - if s:modeAndEXPR() && b:token == 'DOT' - let b:mode = s:EXPR - let pos = b:pos - call s:nextToken() - call s:accept('CLASS') - if b:pos == b:errorEndPos - let name = '' - if b:token == 'IDENTIFIER' - let name = b:name - call s:nextToken() - else - let name = '' - endif - let t = {'tag': 'ERRONEOUS', 'pos': pos, 'errs': [s:Select(pos, t, name)]} - else - let t = s:Select(pos, t, 'class') - endif - elseif s:modeAndTYPE() - let b:mode = s:TYPE - else - call s:SyntaxError('dot.class.expected') - endif - return t -endfu - -" creator {{{2 -fu! s:creator(newpos, typeArgs) - if b:token =~# '^\(BYTE\|SHORT\|CHAR\|INT\|LONG\|FLOAT\|DOUBLE\|BOOLEAN\)$' - if a:typeArgs == [] - return s:arrayCreatorRest(a:newpos, s:basicType()) - endif - endif - - let t = s:qualident() - let oldmode = b:mode - let b:mode = s:TYPE - if b:token == 'LT' - "checkGenerics - let t = s:typeArguments(t) - endif - let b:mode = oldmode - - if b:token == 'LBRACKET' - return s:arrayCreatorRest(a:newpos, t) - elseif b:token == 'LPAREN' - return s:classCreatorRest(a:newpos, {}, a:typeArgs, t) - else - call s:ReportSyntaxError(b:pos, '( or [ expected') - let t = {'tag': 'NEWCLASS', 'encl': {}, 'typeargs': a:typeArgs, 'clazz': t, 'args': [], 'def': {}} - return {'tag': 'ERRONEOUS', 'pos': a:newpos, 'errs': [t]} - endif -endfu - -fu! s:innerCreator(newpos, typeArgs, encl) - let t = s:Ident(b:pos, s:ident()) - if b:token == 'LT' - " checkGenerics - let t = TypeArguments(t) - endif - return s:classCreatorRest(a:newpos, a:encl, a:typeArgs, t) -endfu - -fu! s:arrayCreatorRest(newpos, elemtype) - let elemtype = a:elemtype - call s:accept('LBRACKET') - if b:token == 'RBRACKET' - call s:accept('RBRACKET') - let elemtype = s:bracketsOpt(elemtype) - if b:token == 'LBRACE' - return s:arrayInitializer(a:newpos, elemtype) - else - return s:SyntaxError('array.dimension.missing') - endif - else - let dims = [s:expression()] - call s:accept('RBRACKET') - while b:token == 'LBRACKET' - let pos = b:pos - call s:nextToken() - if b:token == 'RBRACKET' - let elemtype = s:bracketsOptCont(elemtype, pos) - else - call add(dims, s:expression()) - call s:accept('RBRACKET') - endif - endwhile - return {'tag': 'NEWARRAY', 'pos': a:newpos, 'elemtype': elemtype, 'dims': dims, 'elems': {}} - endif -endfu - -fu! s:classCreatorRest(newpos, encl, typeArgs, t) - let args = s:arguments() - let body = {} - if b:token == 'LBRACE' - let body = s:ClassDef(b:pos, {}) - let body.defs = s:classOrInterfaceBody('', 0) - let body.endpos = b:pos - endif - return {'tag': 'NEWCLASS', 'encl': a:encl, 'typeargs': a:typeArgs, 'clazz': a:t, 'args': args, 'def': body} -endfu - -" ArrayInitializer = "{" [VariableInitializer {"," VariableInitializer}] [","] "}" {{{2 -fu! s:arrayInitializer(newpos, t) - call s:accept('LBRACE') - let elems = [] - if b:token == 'COMMA' - call s:nextToken() - elseif b:token != 'RBRACE' - call add(elems, s:variableInitializer()) - while b:token == 'COMMA' - call s:nextToken() - if b:token == 'RBRACE' - break - endif - call add(elems, s:variableInitializer()) - endwhile - endif - call s:accept('RBRACE') - return {'tag': 'NEWARRAY', 'pos': a:newpos, 'elemtype': a:t, 'dims': [], 'elems': elems} -endfu - -" VariableInitializer = ArrayInitializer | Expression {{{2 -fu! s:variableInitializer() - return b:token == 'LBRACE' ? s:arrayInitializer(b:pos, {}) : s:expression() -endfu - -" ParExpression = "(" Expression ")" {{{2 -fu! s:parExpression() - call s:accept('LPAREN') - let t = s:expression() - call s:accept('RPAREN') - return t -endfu - -" {{{2 -" Block = "{" BlockStatements "}" {{{2 -fu! s:block(...) - let t = {'tag': 'BLOCK', 'stats': []} - let t.pos = a:0 > 0 ? a:1 : b:pos - let t.flags = a:0 > 1 ? a:2 : 0 - - call s:accept('LBRACE') - - " scan strategy: ignore statements? - if a:0 > 2 && a:3 - if b:token !=# 'RBRACE' - let b:pos = s:gotoMatchEnd('{', '}', b:token == 'LBRACE') - endif - "let t.stats = Strpart(t.pos, t.endpos-t.pos-1) - else - let t.stats = s:blockStatements() - while b:token == 'CASE' || b:token == 'DEFAULT' - call s:SyntaxError("orphaned") - call s:switchBlockStatementGroups() - endwhile - endif - - let t.endpos = b:pos - call s:accept('RBRACE') - return t -endfu - -" BlockStatements = { BlockStatement } {{{2 -" BlockStatement = LocalVariableDeclarationStatement -" | ClassOrInterfaceOrEnumDeclaration -" | [Ident ":"] Statement -" LocalVariableDeclarationStatement -" = { FINAL | '@' Annotation } Type VariableDeclarators ";" -fu! s:blockStatements() - let lastErrPos = -1 - let stats = [] - while 1 - let pos = b:pos - if b:token =~# '^\(RBRACE\|CASE\|DEFAULT\|EOF\)$' - return stats - elseif b:token =~# '^\(LBRACE\|IF\|FOR\|WHILE\|DO\|TRY\|SWITCH\|SYNCHRONIZED\|RETURN\|THROW\|BREAK\|CONTINUE\|SEMI\|ELSE\|FINALLY\|CATCH\)$' - call add(stats, s:statement()) - elseif b:token =~# '^\(MONKEYS_AT\|FINAL\)' - let dc = b:docComment - let mods = s:modifiersOpt() - if b:token =~# '^\(INTERFACE\|CLASS\|ENUM\)$' - call add(stats, s:classOrInterfaceOrEnumDeclaration(mods, dc)) - else - let t = s:type() - let stats = stats + s:variableDeclarators(mods, t, []) - call s:accept('SEMI') - endif - elseif b:token =~# '^\(ABSTRACT\|STRICTFP\|CLASS\|INTERFACE\|ENUM\)$' - if b:token == 'ENUM' - call s:Log(4, b:pos, 'local.enum') - endif - call add(stats, s:classOrInterfaceOrEnumDeclaration(s:modifiersOpt(), b:docComment)) - elseif b:token == 'ASSERT' - call add(stats, s:statement()) - else - let name = b:name - let t = s:term(s:EXPR_OR_TYPE) - if b:token == 'COLON' && t.tag == 'IDENT' - call s:nextToken() - let stat = s:statement() - call add(stats, {'tag': 'LABELLED', 'pos': b:pos, 'label': name, 'body': stat}) - elseif s:BitAnd(b:lastmode, s:TYPE) && b:token =~# '^\(IDENTIFIER\|ASSERT\|ENUM\)$' - let pos = b:pos - let mods = {} " {'tag': 'MODIFIERS', 'pos': -1, 'flags': 0} - let stats = stats + s:variableDeclarators(mods, t, []) - call s:accept('SEMI') - else - call add(stats, {'tag': 'EXEC', 'pos': pos, 'expr': s:checkExprStat(t)}) " TODO - call s:accept('SEMI') - endif - endif - - if b:pos == lastErrPos - return stats - endif - if b:pos <= b:errorEndPos - call s:skip(0, 1, 1, 1) - let lastErrPos = b:pos - endif - - " resetDeprecatedFlag() - endwhile -endfu - -" Statement = Block {{{2 -" | IF ParExpression Statement [ELSE Statement] -" | FOR "(" ForInitOpt ";" [Expression] ";" ForUpdateOpt ")" Statement -" | FOR "(" FormalParameter : Expression ")" Statement -" | WHILE ParExpression Statement -" | DO Statement WHILE ParExpression ";" -" | TRY Block ( Catches | [Catches] FinallyPart ) -" | SWITCH ParExpression "{" SwitchBlockStatementGroups "}" -" | SYNCHRONIZED ParExpression Block -" | RETURN [Expression] ";" -" | THROW Expression ";" -" | BREAK [Ident] ";" -" | CONTINUE [Ident] ";" -" | ASSERT Expression [ ":" Expression ] ";" -" | ";" -" | ExpressionStatement -" | Ident ":" Statement -" called only by BlockStatements or self -fu! s:statement() - let pos = b:pos - if b:token == 'LBRACE' - return s:block() - elseif b:token == 'IF' - call s:nextToken() - let t = {'tag': 'IF', 'pos': pos, 'cond': s:parExpression(), 'thenpart': s:statement()} - if b:token == 'ELSE' - call s:nextToken() - let t.elsepart = s:statement() - endif - let t.endpos = b:pos - return t - - elseif b:token == 'FOR' - call s:nextToken() - call s:accept('LPAREN') - let inits = b:token == 'SEMI' ? [] : s:forInit() - " foreach - if len(inits) == 1 && inits[0].tag == 'VARDEF' && (!has_key(inits[0], 'init') || inits[0].init == {}) && b:token == 'COLON' - " checkForeach - let var = inits[0] - call s:accept('COLON') - let expr = s:expression() - call s:accept('RPAREN') - let body = s:statement() - return {'tag': 'FOREACHLOOP', 'pos': pos, 'endpos': b:pos, 'var': var, 'expr': expr, 'body': body} - else - call s:accept('SEMI') - let cond = b:token == 'SEMI' ? {} : s:expression() - call s:accept('SEMI') - let steps = b:token == 'RPAREN' ? [] : s:forUpdate() - call s:accept('RPAREN') - let body = s:statement() - return {'tag': 'FORLOOP', 'pos': pos, 'endpos': b:pos, 'init': inits, 'cond': cond, 'step': steps, 'body': body} - endif - - elseif b:token == 'WHILE' - call s:nextToken() - let cond = s:parExpression() - let body = s:statement() - return {'tag': 'WHILELOOP', 'pos': pos, 'endpos': b:pos, 'cond': cond, 'body': body} - - elseif b:token == 'DO' - call s:nextToken() - let body = s:statement() - call s:accept('WHILE') - let cond = s:parExpression() - let t = {'tag': 'DOLOOP', 'pos': pos, 'endpos': b:pos, 'cond': cond, 'body': body} - call s:accept('SEMI') - return t - - elseif b:token == 'TRY' - call s:nextToken() - let body = s:block() - let catchers = [] - let finalizer = {} - if b:token == 'CATCH' || b:token == 'FINALLY' - while b:token == 'CATCH' - call add(catchers, s:catchClause()) - endwhile - if b:token == 'FINALLY' - call s:nextToken() - let finalizer = s:block() - endif - else - call s:Log(4, b:pos, 'try.without.catch.or.finally') - endif - return {'tag': 'TRY', 'pos': pos, 'endpos': b:pos, 'body': body, 'catchers': catchers, 'finalizer': finalizer} - - elseif b:token == 'SWITCH' - call s:nextToken() - let selector = s:parExpression() - call s:accept('LBRACE') - let cases = s:switchBlockStatementGroups() - call s:accept('RBRACE') - return {'tag': 'SWITCH', 'pos': pos, 'endpos': b:pos, 'selector': selector, 'cases': cases} - - elseif b:token == 'SYNCHRONIZED' - call s:nextToken() - let lock = s:parExpression() - let body = s:block() - return {'tag': 'SYNCHRONIZED', 'pos': pos, 'endpos': b:pos, 'lock': lock, 'cases': body} - - elseif b:token == 'RETURN' - call s:nextToken() - let result = b:token == 'SEMI' ? {} : s:expression() - call s:accept('SEMI') - return {'tag': 'RETURN', 'pos': pos, 'endpos': b:pos, 'expr': result} - - elseif b:token == 'THROW' - call s:nextToken() - let exc = s:expression() - call s:accept('SEMI') - return {'tag': 'THROW', 'pos': pos, 'endpos': b:pos, 'expr': exc} - - elseif b:token == 'BREAK' || b:token == 'CONTINUE' - let token = b:token - call s:nextToken() - let label = b:token =~# '^\(IDENTIFIER\|ASSERT\|ENUM\)$' ? s:ident() : '' - call s:accept('SEMI') - return {'tag': token, 'pos': pos, 'endpos': b:pos, 'label': label} - - elseif b:token == 'SEMI' - call s:nextToken() - return {'tag': 'SKIP', 'pos': pos} - - elseif b:token == 'ELSE' - return s:SyntaxError("else.without.if") - elseif b:token == 'FINALLY' - return s:SyntaxError("finally.without.try") - elseif b:token == 'CATCH' - return s:SyntaxError("catch.without.try") - - elseif b:token == 'ASSERT' - "if b:allowAsserts && b:token == 'ASSERT' - call s:nextToken() - let t = {'tag': 'ASSERT', 'pos': pos, 'cond': s:expression()} - if b:token == 'COLON' - call s:nextToken() - let t.detail = s:expression() - endif - call s:accept('SEMI') - let t.endpos = b:pos - return t - "endif - - else " also ENUM - let name = b:name - let expr = s:expression() - if b:token == 'COLON' && expr.tag == 'IDENT' - call s:nextToken() - let stat = s:statement() - return {'tag': 'LABELLED', 'pos': pos, 'endpos': b:pos, 'label': name, 'body': stat} - else - let stat = {'tag': 'EXEC', 'pos': pos, 'endpos': b:pos, 'expr': s:checkExprStat(expr)} - call s:accept('SEMI') - return stat - endif - endif -endfu - -" CatchClause = CATCH "(" FormalParameter ")" Block -fu! s:catchClause() - let pos = b:pos - call s:accept('CATCH') - call s:accept('LPAREN') - let formal = s:variableDeclaratorId(s:optFinalParameter(), s:qualident()) - call s:accept('RPAREN') - let body = s:block() - return {'tag': 'CATCH', 'pos': pos, 'endpos': b:pos, 'param': formal, 'body': body} -endfu - -" SwitchBlockStatementGroups = { SwitchBlockStatementGroup } -" SwitchBlockStatementGroup = SwitchLabel BlockStatements -" SwitchLabel = CASE ConstantExpression ":" | DEFAULT ":" -fu! s:switchBlockStatementGroups() - let cases = [] - while 1 - let pos = b:pos - if b:token == 'CASE' || b:token == 'DEFAULT' - let token = b:token - call s:nextToken() - let pat = token == 'CASE' ? s:expression() : {} - call s:accept('COLON') - let stats = s:blockStatements() - call add(cases, {'tag': 'CASE', 'pos': pos, 'pat': pat, 'stats': stats}) - elseif b:token == 'RBRACE' || b:token == 'EOF' - return cases - else - call s:nextToken() - call s:SyntaxError('case.default.rbrace.expected') - endif - endwhile -endfu - -" MoreStatementExpressions = { COMMA StatementExpression } -fu! s:moreStatementExpressions(pos, first, stats) - call add(a:stats, {'tag': 'EXEC', 'pos': a:pos, 'expr': s:checkExprStat(a:first)}) - while b:token == 'COMMA' - call s:nextToken() - let pos = b:pos - let t = s:expression() - call add(a:stats, {'tag': 'EXEC', 'pos': pos, 'expr': s:checkExprStat(t)}) - endwhile - return a:stats -endfu - -" ForInit = StatementExpression MoreStatementExpressions -" | { FINAL | '@' Annotation } Type VariableDeclarators -fu! s:forInit() - let stats = [] - let pos = b:pos - if b:token == 'FINAL' || b:token == 'MONKEYS_AT' - return s:variableDeclarators(s:optFinal(0), s:type(), stats) - else - let t = s:term(s:EXPR_OR_TYPE) - if s:BitAnd(b:lastmode, s:TYPE) && b:token =~# '^\(IDENTIFIER\|ASSERT\|ENUM\)$' - return s:variableDeclarators(s:modifiersOpt(), t, stats) - else - return s:moreStatementExpressions(pos, t, stats) - endif - endif -endfu - -" ForUpdate = StatementExpression MoreStatementExpressions -fu! s:forUpdate() - return s:moreStatementExpressions(b:pos, s:expression(), []) -endfu - -" ModifiersOpt = { Modifier } {{{2 -" Modifier = PUBLIC | PROTECTED | PRIVATE | STATIC | ABSTRACT | FINAL -" | NATIVE | SYNCHRONIZED | TRANSIENT | VOLATILE | "@" -" | "@" Annotation -" NOTE: flags is a string, not a long number -fu! s:modifiersOpt(...) - let partial = a:0 == 0 ? {} : a:1 - - let flags = partial == {} ? 0 : partial.flags - let annotations = partial == {} ? [] : partial.annotations - " TODO: deprecatedFlag - - let pos = b:pos - let lastPos = -1 - while 1 - let flag = 0 - if b:token =~# '^\(PUBLIC\|PROTECTED\|PRIVATE\|STATIC\|ABSTRACT\|FINAL\|NATIVE\|SYNCHRONIZED\|TRANSIENT\|VOLATILE\|STRICTFP\|MONKEYS_AT\)$' - let flag = b:token == 'MONKEYS_AT' ? s:Flags.ANNOTATION : get(s:Flags, b:token, 0) - else - break - endif - "if s:BitAnd(flags, flag) != 0 - " "log.error(S.pos(), "repeated.modifier") - "endif - - let lastPos = b:pos - call s:nextToken() - - if flag == s:Flags.ANNOTATION - "call s:checkAnnotations() - if b:token != 'INTERFACE' - let ann = s:annotation(lastPos) - if flags == 0 && annotations == [] - let pos = ann.pos - endif - call add(annotations, ann) - let lastPos = ann.pos - let flag = 0 - endif - endif - let flags = s:BitOr(flags, flag) - endwhile - - if b:token == 'ENUM' - let flags = s:BitOr(flags, s:Flags.ENUM) - elseif b:token == 'INTERFACE' - let flags = s:BitOr(flags, s:Flags.INTERFACE) - endif - - if flags == 0 && empty(annotations) - let pos = -1 - endif - - return {'tag': 'MODIFIERS', 'pos': pos, 'flags': flags, 'annotations': annotations} -endfu - -" Annotation = "@" Qualident [ "(" AnnotationFieldValues ")" ] {{{2 -fu! s:annotation(pos) - "call s:checkAnnotations() - let ident = s:qualident() - "let endPos = b:prevEndPos - let fieldValues = s:annotationFieldValuesOpt() - - return {'tag': 'ANNOTATION', 'pos': a:pos, 'annotationType': ident, 'args': fieldValues} -endfu - -fu! s:annotationFieldValuesOpt() - return b:token == 'LPAREN' ? s:annotationFieldValues() : [] -endfu - -" AnnotationFieldValues = "(" [ AnnotationFieldValue { "," AnnotationFieldValue } ] ")" -fu! s:annotationFieldValues() - let buf = [] - call s:accept('LPAREN') - if b:token != 'RPAREN' - call add(buf, s:annotationFieldValue()) - while b:token == 'COMMA' - call s:nextToken() - call add(buf, s:annotationFieldValue()) - endwhile - endif - call s:accept('RPAREN') - return buf -endfu - -" AnnotationFieldValue = AnnotationValue | Identifier "=" AnnotationValue -fu! s:annotationFieldValue() - call s:Trace('s:annotationFieldValue ' . b:token) - if b:token == 'IDENTIFIER' - let b:mode = s:EXPR - let t1 = s:term1() - if t1.tag == 'IDENT' && b:token == 'EQ' - let pos = b:pos - call s:accept('EQ') - return {'tag': 'ASSIGN', 'pos': pos, 'lhs': t1, 'rhs': s:annotationValue()} - else - return t1 - endif - endif - return s:annotationValue() -endfu - -" AnnotationValue = ConditionalExpression | Annotation | "{" [ AnnotationValue { "," AnnotationValue } ] "}" -fu! s:annotationValue() - let pos = 0 - if b:token == 'MONKEYS_AT' - let pos = b:bp - call s:nextToken() - return s:annotation(pos) - elseif b:token == 'LBRACE' - let pos = b:pos - call s:accept('LBRACE') - let buf = [] - if b:token != 'RBRACE' - call add(buf, s:annotationValue()) - while b:token == 'COMMA' - call s:nextToken() - if b:token == 'RPAREN' - break - endif - call add(buf, s:annotationValue()) - endwhile - endif - call s:accept('RBRACE') - return buf - else - let b:mode = s:EXPR - return s:term1() - endif -endfu - -" AnnotationsOpt = { '@' Annotation } -fu! s:annotationsOpt() - if b:token != 'MONKEYS_AT' - return [] - endif - - let buf = [] - while b:token != 'MONKEYS_AT' - let pos = b:pos - call s:nextToken() - call add(buf, s:annotation(pos)) - endwhile - return buf -endfu - -" {{{2 -" CompilationUnit {{{2 -" CompilationUnit = [ { "@" Annotation } PACKAGE Qualident ";"] {ImportDeclaration} {TypeDeclaration} -fu! s:compilationUnit() - let unit = {'tag': 'TOPLEVEL', 'pos': b:pos} - - let mods = {} - if b:token == 'MONKEYS_AT' - let mods = s:modifiersOpt() - endif - - if b:token == 'PACKAGE' - if mods != {} - " checkNoMods(mods.flags) - let unit.packageAnnotations = mods.annotations - let mods = {} - endif - call s:nextToken() - let unit.pid = s:qualident() - let unit.package = java_parser#type2Str(unit.pid) - call s:accept('SEMI') - endif - - let imports = [] - let s:types = [] - let checkForImports = 1 - while b:token != 'EOF' - if b:pos <= b:errorEndPos - call s:skip(checkForImports, 0, 0, 0) - if b:token == 'EOF' - break - endif - endif - if checkForImports && mods == {} && b:token == 'IMPORT' - call add(imports, s:importDeclaration()) - else - let def = s:typeDeclaration(mods) - "if (def instanceof JCExpressionStatement) - " def = ((JCExpressionStatement)def).expr - "endif - call add(s:types, def) - if def.tag == 'CLASSDEF' - let checkForImports = 0 - endif - let mods = {} - endif - endwhile - let unit.imports = imports - let unit.types = s:types - unlet s:types - - return unit -endfu - -" ImportDeclaration = IMPORT [ STATIC ] Ident { "." Ident } [ "." "*" ] ";" {{{2 -" return fqn -fu! s:importDeclaration() - " OAO: Usualy it is in one line. - if b:scanStrategy < 0 - let idx = matchend(b:lines[b:line], '\(\s\+static\>\)\?\s\+\([_$a-zA-Z][_$a-zA-Z0-9_]*\)\(\s*\.\s*[_$a-zA-Z][_$a-zA-Z0-9_]*\)*\(\s*\.\s*\*\)\?;') - if idx != -1 - let fqn = strpart(b:lines[b:line], b:col, idx-b:col-1) - let b:col = idx - let b:bp = b:idxes[b:line] + b:col - call s:nextToken() - return fqn - endif - endif - - - call s:Info('==import==') - let pos = b:pos - call s:nextToken() - - let importStatic = 0 - if b:token == 'STATIC' - " checkStaticImports() - let importStatic = 1 - call s:nextToken() - endif - - let pid = s:Ident(b:pos, s:ident()) - - " - let pos1 = b:pos - call s:accept('DOT') - if b:token == 'STAR' - let pid = s:Select(pos1, pid, '*') - call s:nextToken() - else - let pid = s:Select(pos1, pid, s:ident()) - endif - while b:token == 'DOT' - let pos1 = b:pos - call s:accept('DOT') - if b:token == 'STAR' - let pid = s:Select(pos1, pid, '*') - call s:nextToken() - break - else - let pid = s:Select(pos1, pid, s:ident()) - endif - endwhile - let fqn = java_parser#type2Str(pid) - if b:token != 'SEMI' - let fqn .= '' - endif - call s:accept('SEMI') - "return {'tag': 'IMPORT', 'pos': b:pos, 'qualid': pid, 'staticImport': importStatic} - return fqn -endfu - -" TypeDeclaration = ClassOrInterfaceOrEnumDeclaration | ";" {{{2 -fu! s:typeDeclaration(mods) - let pos = b:pos - if a:mods == {} && b:token == 'SEMI' - call s:nextToken() - return {'tag': 'SKIP', 'pos': pos} - else - let dc = b:docComment - let mods = s:modifiersOpt(a:mods) - return s:classOrInterfaceOrEnumDeclaration(mods, dc) - endif -endfu - -fu! s:classOrInterfaceOrEnumDeclaration(mods, dc) - call s:Info('== type ==') - if b:token == 'CLASS' - return s:classDeclaration(a:mods, a:dc) - elseif b:token == 'INTERFACE' - return s:interfaceDeclaration(a:mods, a:dc) - elseif b:token == 'ENUM' - "if !exists('b:allowEnums') || !b:allowEnums - " call s:SyntaxError("enums.not.supported.in.source") - "endif - return s:enumDeclaration(a:mods, a:dc) - else - let pos = b:pos - let errs = [] - if b:token == 'IDENTIFIER' - call add(errs, s:ident()) - call s:setErrorEndPos(b:bp) - endif - return s:SyntaxError("class.or.intf.or.enum.expected", pos, errs) - endif -endfu - -" ClassDeclaration = CLASS Ident TypeParametersOpt [EXTENDS Type] [IMPLEMENTS TypeList] ClassBody {{{2 -fu! s:classDeclaration(mods, dc) - let type = s:ClassDef(b:pos, a:mods) - - call s:accept('CLASS') - let type.name = s:ident() - - let type.typarams = s:typeParametersOpt() - - " extends - if b:token == 'EXTENDS' - call s:nextToken() - let type.extends = [s:type()] - endif - - " implements - if b:token == 'IMPLEMENTS' - call s:nextToken() - let type.implements = s:typeList() - endif - - let type.defs = s:classOrInterfaceBody(type.name, 0) - let type.endpos = b:pos - return type -endfu - -" InterfaceDeclaration = INTERFACE Ident TypeParametersOpt [EXTENDS TypeList] InterfaceBody {{{2 -fu! s:interfaceDeclaration(mods, dc) - let type = s:ClassDef(b:pos, a:mods) - - call s:accept('INTERFACE') - let type.name = s:ident() - - let type.typarams = s:typeParametersOpt() - - " extends - if b:token == 'EXTENDS' - call s:nextToken() - let type.extends = s:typeList() - endif - - let type.defs = s:classOrInterfaceBody(type.name, 1) - let type.endpos = b:pos - return type -endfu - -" EnumDeclaration = ENUM Ident [IMPLEMENTS TypeList] EnumBody {{{2 -fu! s:enumDeclaration(mods, dc) - let type = s:ClassDef(b:pos, a:mods) - - call s:accept('ENUM') - let type.name = s:ident() - - if b:token == 'IMPLEMENTS' - call s:nextToken() - let type.implements = s:typeList() - endif - - let type.defs = s:enumBody(type.name) - let type.endpos = b:pos - return type -endfu - -" EnumBody = "{" { EnumeratorDeclarationList } [","] -" [ ";" {ClassBodyDeclaration} ] "}" -fu! s:enumBody(enumName) - let defs = [] - call s:accept('LBRACE') - - if b:token == 'COMMA' - call s:nextToken() - elseif b:token != 'RBRACE' && b:token != 'SEMI' - call add(defs, s:enumeratorDeclaration(a:enumName)) - while b:token == 'COMMA' - call s:nextToken() - if b:token == 'RBRACE' || b:token == 'SEMI' - break - endif - call add(defs, s:enumeratorDeclaration(a:enumName)) - endwhile - if b:token != 'RBRACE' && b:token != 'SEMI' - call s:SyntaxError('comma.or.rbrace.or.semi. expected') - call s:nextToken() - endif - endif - - if b:token == 'SEMI' - call s:nextToken() - while b:token != 'RBRACE' && b:token != 'EOF' - call add(defs, s:classOrInterfaceBodyDeclaration(a:enumName, 0)) - if b:pos <= b:errorEndPos - call s:skip(0, 1, 1, 0) - endif - endwhile - endif - - call s:accept('RBRACE') - return defs -endfu - -" EnumeratorDeclaration = AnnotationsOpt [TypeArguments] IDENTIFIER [ Arguments ] [ "{" ClassBody "}" ] -fu! s:enumeratorDeclaration(enumName) - let vardef = {'tag': 'VARDEF', 'pos': b:pos} - - let dc = b:docComment - let flags = 16409 " s:BitOr(s:Flags.PUBLIC, s:Flags.STATIC, s:Flags.FINAL, s:Flags.ENUM) - " if b:deprecatedFlag - " let flags = 147481 " s:BitOr(flags, s:Flags.DEPRECATED) - " let b:deprecatedFlag = 1 - " endif - let pos = b:pos - let annotations = s:annotationsOpt() - let vardef.mods = s:Modifiers(pos, flags, annotations) - let vardef.mods.pos = empty(annotations) ? -1 : pos - let vardef.m = s:Number2Bits(flags) - - let typeArgs = s:typeArgumentsOpt() - let identPos = b:pos - let vardef.name = s:ident() - let vardef.n = vardef.name - - let args = b:token == 'LPAREN' ? s:arguments() : [] - - " NOTE: It may be either a class body or a method body. I dont care, just record it - if b:token == 'LBRACE' - "call s:accept('LBRACE') - "if b:token !=# 'RBRACE' - " call s:gotoMatchEnd('{', '}') - "endif - "call s:accept('RBRACE') - - "let mods1 = s:Modifiers(-1, s:BitOr(s:Flags.ENUM, s:Flags.STATIC), []) - let defs = s:classOrInterfaceBody('', 0) - "let body = s:ClassDef(identPos, mods1) - "let body.defs = defs - endif - let vardef.endpos = b:bp - - " TODO: create new class - - return vardef -endfu - -" classOrInterfaceBody {{{2 -" ClassBody = "{" {ClassBodyDeclaration} "}" -" InterfaceBody = "{" {InterfaceBodyDeclaration} "}" -fu! s:classOrInterfaceBody(classname, isInterface) - call s:Info('== type definition body ==') - call s:accept('LBRACE') - - if b:pos <= b:errorEndPos - call s:skip(0, 1, 0, 0) - if b:token == 'LBRACE' - call s:nextToken() - endif - endif - - let defs = [] - while b:token != 'RBRACE' && b:token != 'EOF' - let defs += s:classOrInterfaceBodyDeclaration(a:classname, a:isInterface) - - if b:pos <= b:errorEndPos - call s:skip(0, 1, 1, 0) - endif - endwhile - call s:accept('RBRACE') - return defs -endfu - -" classOrInterfaceBodyDeclaration {{{2 -" ClassBodyDeclaration = -" ";" -" | [STATIC] Block -" | ModifiersOpt -" ( Type Ident -" ( VariableDeclaratorsRest ";" | MethodDeclaratorRest ) -" | VOID Ident MethodDeclaratorRest -" | TypeParameters (Type | VOID) Ident MethodDeclaratorRest -" | Ident ConstructorDeclaratorRest -" | TypeParameters Ident ConstructorDeclaratorRest -" | ClassOrInterfaceOrEnumDeclaration -" ) -" InterfaceBodyDeclaration = -" ";" -" | ModifiersOpt Type Ident -" ( ConstantDeclaratorsRest | InterfaceMethodDeclaratorRest ";" ) -fu! s:classOrInterfaceBodyDeclaration(classname, isInterface) - call s:Info('s:classOrInterfaceBodyDeclaration') - if b:token == 'SEMI' - call s:nextToken() - return [{'tag': 'BLOCK', 'pos': -1, 'endpos': -1, 'stats': []}] - else - if b:scanStrategy < 0 - let result = s:classOrInterfaceBodyDeclaration_opt(a:classname, a:isInterface) - if !empty(result) - return result - endif - endif - - - let dc = b:docComment - let pos = b:bp - let mods = s:modifiersOpt() - - if b:token =~# '^\(CLASS\|INTERFACE\|ENUM\)$' - return [s:classOrInterfaceOrEnumDeclaration(mods, dc)] - - " [STATIC] block - elseif b:token == 'LBRACE' && !a:isInterface - return [s:block(pos, mods.flags, b:scanStrategy < 1)] - - else - let typarams = s:typeParametersOpt() - - let token = b:token - let name = b:name - - let type = copy(s:TTree) - let isVoid = b:token == 'VOID' - if isVoid - let type = {'tag': 'TYPEIDENT', 'pos': pos, 'typetag': 'void'} " FIXME - let type.value = '' - call s:nextToken() - else - let time = reltime() - let type = s:type() - let b:et_perf .= "\r" . reltimestr(reltime(time)) . ' s:type() ' - endif - - - " ctor - if b:token == 'LPAREN' && !a:isInterface && type.tag == 'IDENT' - if a:isInterface || name != a:classname - call s:SyntaxError('invalid.meth.decl.ret.type.req') - endif - return [s:methodDeclaratorRest(pos, mods, type, name, typarams, a:isInterface, 1, dc)] - else - let name = s:ident() - " method - if b:token == 'LPAREN' - return [s:methodDeclaratorRest(pos, mods, type, name, typarams, a:isInterface, isVoid, dc)] - " field - elseif !isVoid && len(typarams) == 0 - let defs = s:variableDeclaratorsRest(pos, mods, type, name, a:isInterface, dc, copy([])) - call s:accept('SEMI') - return defs - else - call s:SyntaxError("LPAREN expected") - return [{}] - endif - endif - endif - endif -endfu - -" OAO: short way for common declaration of field or method, not for generic type yet. -fu! s:classOrInterfaceBodyDeclaration_opt(classname, isInterface) - let str = b:lines[b:line] - let idx = matchend(str, s:RE_MEMBER_HEADER) - if idx != -1 - let subs = split(substitute(strpart(str, 0, idx), s:RE_MEMBER_HEADER, '\1;\2;\3', ''), ';') - let name_ = subs[2] - let type_ = subs[1] - let flag_ = s:String2Flags(subs[0]) - -" if type_ =~# '^\(class\|interface\|enum\)$' -" return [s:classOrInterfaceOrEnumDeclaration(mods, dc)] -" else - " methodDeclarator - let idx = matchend(str, '^\s*[,=;(]', idx)-1 - if str[idx] == '(' - let methoddef = s:methodDeclaratorRest_opt(b:pos, flag_, type_, name_, [], a:isInterface, type_ == 'void', '', str, idx) - if !empty(methoddef) - return [methoddef] - endif - - " variableDeclarator - elseif str[idx] =~ '[=;]' - let vardef = {'tag': 'VARDEF', 'pos': b:pos, 'name': name_, 'n': name_, 'vartype': type_, 't': type_, 'm': flag_} - call s:gotoSemi() - call s:accept('SEMI') - let vardef.pos_end = b:pos - return [vardef] - - " variableDeclarators - elseif str[idx] == ',' - let ie = matchend(str, '^\(,\s*'. s:RE_IDENTIFIER .'\s*\)*;', idx) - if ie != -1 - let vardef = {'tag': 'VARDEF', 'pos': b:pos, 'name': name_, 'n': name_, 'vartype': type_, 't': type_, 'm': flag_} - let vars = [vardef] - for item in split(substitute(strpart(str, idx+1, ie-idx-2), '\s', '', 'g'), ',') - let vardef = copy(vardef) - let vardef.name = item - let vardef.n = item - call add(vars, vardef) - endfor - let b:col = ie - let b:bp = b:idxes[b:line] + b:col - call s:nextToken() - return vars - endif - endif -" endif - endif - - let RE_CTOR_HEADER = '^\s*\(\(public\|protected\|private\)\s\+\)\=\C' .a:classname. '\s*(' - let ie = matchend(str, RE_CTOR_HEADER) - if ie != -1 && !a:isInterface - let flag_ = s:String2Flags(substitute(strpart(str, 0, ie), RE_CTOR_HEADER, '\1', '')) - let methoddef = s:methodDeclaratorRest_opt(b:pos, flag_, a:classname, a:classname, [], a:isInterface, 1, '', str, ie-1) - if !empty(methoddef) - return [methoddef] - endif - endif - - let RE_METHOD_HEADER = '^\s*\(' .s:RE_IDENTIFIER. '\%(\s*\.\s*' .s:RE_IDENTIFIER. '\)*\%(\s*\[\s*\]\)\=\)\s\+\(' .s:RE_IDENTIFIER. '\)\s*(' - let ie = matchend(str, RE_METHOD_HEADER) - if ie != -1 - let subs = split(substitute(strpart(str, 0, ie), RE_METHOD_HEADER, '\1;\2', ''), ';') - let methoddef = s:methodDeclaratorRest_opt(b:pos, 0, subs[0], subs[1], [], a:isInterface, subs[0] == 'void', '', str, ie-1) - if !empty(methoddef) - return [methoddef] - endif - endif -endfu - - -" MethodDeclaratorRest = {{{2 -" FormalParameters BracketsOpt [Throws TypeList] ( MethodBody | [DEFAULT AnnotationValue] ";") -" VoidMethodDeclaratorRest = FormalParameters [Throws TypeList] ( MethodBody | ";") -" InterfaceMethodDeclaratorRest = FormalParameters BracketsOpt [THROWS TypeList] ";" -" VoidInterfaceMethodDeclaratorRest = FormalParameters [THROWS TypeList] ";" -" ConstructorDeclaratorRest = "(" FormalParameterListOpt ")" [THROWS TypeList] MethodBody -fu! s:methodDeclaratorRest(pos, mods, type, name, typarams, isInterface, isVoid, dc) - let time = reltime() - let methoddef = {'tag': 'METHODDEF', 'pos': a:pos, 'name': a:name, 'mods': a:mods, 'restype': a:type, 'typarams': a:typarams} - let methoddef.n = a:name - let methoddef.m = s:Number2Bits(a:mods.flags) - let methoddef.r = java_parser#type2Str(a:type) - - " parameters - let methoddef.params = s:formalParameters() - - " BracketsOpt - if !a:isVoid - let methoddef.r = java_parser#type2Str(s:bracketsOpt(a:type)) - endif - - - " throws - if b:token == 'THROWS' - call s:nextToken() - - " thrown = qualidentList() - let ts = [s:qualident()] - while b:token == 'COMMA' - call s:nextToken() - call add(ts, s:qualident()) - endwhile - let methoddef.throws = ts - endif - - " method body - if b:token == 'LBRACE' - let methoddef.body = s:block(b:pos, 0, b:scanStrategy < 1) - else - if b:token == 'DEFAULT' - call s:accept('DEFAULT') - let methoddef.defaultValue = s:annotationValue() - endif - call s:accept('SEMI') - - if b:pos <= b:errorEndPos - call s:skip(0, 1, 0, 0) - if b:token == 'LBRACE' - let methoddef.body = s:block(b:pos, 0, b:scanStrategy < 1) - endif - endif - endif - - let methoddef.d = s:method2Str(methoddef) - let b:et_perf .= "\r" . reltimestr(reltime(time)) . ' methodrest() ' - return methoddef -endfu - -" method header declared in one line, -" NOTE: RE_FORMAL_PARAM_LIST do not recognize varargs and nested comments -fu! s:methodDeclaratorRest_opt(pos, mods, type, name, typarams, isInterface, isVoid, dc, str, idx) - let str = a:str - let idx = a:idx - - " params - let idxend = matchend(str, '^(\s*)', idx) " no params - if idxend == -1 - let idxend = matchend(str, '^(\s*' . s:RE_FORMAL_PARAM_LIST . '\s*)', idx) - endif - if idxend == -1 - return - endif - - let methoddef = {'tag': 'METHODDEF', 'pos': a:pos, 'name': a:name, 'n': a:name, 'm': a:mods, 'r': a:type} - - " params - let methoddef.params = [] - let s = strpart(str, idx+1, idxend-idx-2) - if s !~ '^\s*$' - for item in split(s, ',') - let subs = split(substitute(item, s:RE_FORMAL_PARAM2, '\2;\5', ''), ';') - let param = {'tag': 'VARDEF', 'pos': -1} - let param.name = subs[1] - let param.vartype = substitute(subs[0], ' ', '', 'g') - let param.m = s:Flags.PARAMETER - call add(methoddef.params, param) - endfor - endif - - " throws - let idx2 = matchend(str, '^\s*' . s:RE_THROWS, idxend) - let idx = idx2 == -1 ? idxend : idx2 - if idx2 != -1 - "let throws = strpart(str, idxend, idx-idxend) - endif - - " in interface - if a:isInterface - let idx = matchend(str, '^\s*;', idx) - if idx != -1 - let b:token = 'SEMI' - let b:col = idx - let b:bp = b:idxes[b:line] + b:col - let b:pos = b:bp - 1 - let methoddef.d = substitute(str, '^\s*\([^{]*\)\s*;\=$', '\1', '') - return methoddef - endif - endif - - let idx = matchend(str, '^\s*{', idx) - if idx == -1 - let idx = matchend(b:lines[b:line+1], '^\s*{') - if idx != -1 - let b:line += 1 - endif - endif - if idx != -1 - let b:token = 'LBRACE' - let b:col = idx - let b:bp = b:idxes[b:line] + b:col - let b:pos = b:bp - 1 - let methoddef.d = substitute(str, '^\s*\([^{]*\)\s*{\=$', '\1', '') - let methoddef.body = s:block(b:pos, 0, b:scanStrategy < 1) - return methoddef - endif -endfu - -" VariableDeclarators = VariableDeclarator { "," VariableDeclarator } {{{2 -fu! s:variableDeclarators(mods, type, vdefs) - return s:variableDeclaratorsRest(b:pos, a:mods, a:type, s:ident(), 0, '', a:vdefs) -endfu - -" VariableDeclaratorsRest = VariableDeclaratorRest { "," VariableDeclarator } -" ConstantDeclaratorsRest = ConstantDeclaratorRest { "," ConstantDeclarator } -fu! s:variableDeclaratorsRest(pos, mods, type, name, reqInit, dc, vdefs) - call add(a:vdefs, s:variableDeclaratorRest(a:pos, a:mods, a:type, a:name, a:reqInit, a:dc)) - while b:token == 'COMMA' - call s:nextToken() - call add(a:vdefs, s:variableDeclarator(a:mods, a:type, a:reqInit, a:dc)) - endwhile - return a:vdefs -endfu - -" VariableDeclarator = Ident VariableDeclaratorRest -" ConstantDeclarator = Ident ConstantDeclaratorRest -fu! s:variableDeclarator(mods, type, reqInit, dc) - return s:variableDeclaratorRest(b:pos, a:mods, a:type, s:ident(), a:reqInit, a:dc) -endfu - -" VariableDeclaratorRest = BracketsOpt ["=" VariableInitializer] -" ConstantDeclaratorRest = BracketsOpt "=" VariableInitializer -fu! s:variableDeclaratorRest(pos, mods, type, name, reqInit, dc) - let vardef = s:VarDef(a:pos, a:mods, a:name, s:bracketsOpt(a:type)) - let vardef.n = vardef.name - let vardef.m = a:mods == {} ? '0' : s:Number2Bits(a:mods.flags) - let vardef.t = java_parser#type2Str(vardef.vartype) - - if b:token == 'EQ' - call s:nextToken() - call s:Info('field init ' . b:token) - let vardef.init = s:variableInitializer() - elseif a:reqInit - echo '[syntax error]:' . s:token2string('EQ') . " expected" - endif - - let vardef.endpos = b:pos - return vardef -endfu - -fu! s:variableDeclaratorId(mods, type) - let vardef = s:VarDef(b:pos, a:mods, s:ident(), a:type) - if len(a:mods.flags) <= 34 " (a:mods.flags & s:Flags.VARARGS) == 0 - let vardef.type = s:bracketsOpt(vardef.vartype) - endif - return vardef -endfu - -" {{{2 -" TypeParametersOpt = ["<" TypeParameter {"," TypeParameter} ">"] {{{2 -fu! s:typeParametersOpt() - if b:token == 'LT' - "call checkGenerics() - let typarams = [] - call s:nextToken() - call add(typarams, s:typeParameter()) - while b:token == 'COMMA' - call s:nextToken() - call add(typarams, s:typeParameter()) - endwhile - call s:accept('GT') - return typarams - else - return [] - endif -endfu - -" TypeParameter = TypeVariable [TypeParameterBound] {{{2 -" TypeParameterBound = EXTENDS Type {"&" Type} -" TypeVariable = Ident -fu! s:typeParameter() - let pos = b:pos - let name = s:ident() - let bounds = [] - if b:token == 'EXTENDS' - call s:nextToken() - call add(bounds, s:type()) - while b:token == 'AMP' - call s:nextToken() - call add(bounds, s:type()) - endwhile - endif - - return {'tag': 'TYPEPARAMETER', 'pos': pos, 'name': name, 'bounds': bounds} -endfu - -" FormalParameters = "(" [ FormalParameterList ] ")" {{{2 -" FormalParameterList = [ FormalParameterListNovarargs , ] LastFormalParameter -" FormalParameterListNovarargs = [ FormalParameterListNovarargs , ] FormalParameter -fu! s:formalParameters() - let params = [] - let lastParam = {} - call s:accept('LPAREN') - if b:token != 'RPAREN' - let lastParam = s:formalParameter() - call add(params, lastParam) - while b:token == 'COMMA' && len(lastParam.mods.flags) <= 34 " (lastParam.mods.flags & s:Flags.VARARGS) == 0 - call s:nextToken() - let lastParam = s:formalParameter() - call add(params, lastParam) - endwhile - endif - call s:accept('RPAREN') - return params -endfu - -" FormalParameter = { FINAL | '@' Annotation } Type VariableDeclaratorId {{{2 -" LastFormalParameter = { FINAL | '@' Annotation } Type '...' Ident | FormalParameter -fu! s:optFinal(flags) - let mods = s:modifiersOpt() - " checkNoMods(mods.flags & ~(Flags.FINAL | Flags.DEPRECATED)) - let mods.flags = s:BitOr(mods.flags, a:flags) - return mods -endfu - -" OAO: optional FINAL for parameter -fu! s:optFinalParameter() - let mods = {'tag': 'MODIFIERS', 'pos': b:pos, 'flags': s:Flags.PARAMETER, 'annotations': []} - if b:token == 'FINAL' - let mods.flags = '1000000000000000000000000000010000' - call s:nextToken() - endif - return mods -endfu - -fu! s:formalParameter() - let mods = s:optFinalParameter() - let type = s:type() - - if b:token == 'ELLIPSIS' - " checkVarargs() - let mods.flags = '1' . mods.flags " s:BitOr_binary(mods.flags, s:Flags.VARARGS) - let type = s:TypeArray(b:pos, type) - call s:nextToken() - endif - - return s:variableDeclaratorId(mods, type) -endfu - -" {{{2 -" auxiliary methods {{{2 -let s:MapToken2Tag = {'BARBAR': 'OR', 'AMPAMP': 'AND', 'BAR': 'BITOR', 'BAREQ': 'BITOR_ASG', 'CARET': 'BITXOR', 'CARETEQ': 'BITXOR_ASG', 'AMP': 'BITAND', 'AMPEQ': 'BITAND_ASG', 'EQEQ': 'EQ', 'BANGEQ': 'NE', 'LT': 'LT', 'GT': 'GT', 'LTEQ': 'LE', 'GTEQ': 'GE', 'LTLT': 'SL', 'LTLTEQ': 'SL_ASG', 'GTGT': 'SR', 'GTGTEQ': 'SR_ASG', 'GTGTGT': 'USR', 'GTGTGTEQ': 'USR_ASG', 'PLUS': 'PLUS', 'PLUSEQ': 'PLUS_ASG', 'SUB': 'MINUS', 'SUBEQ': 'MINUS_ASG', 'STAR': 'MUL', 'STAREQ': 'MUL_ASG', 'SLASH': 'DIV', 'SLASHEQ': 'DIV_ASG', 'PERCENT': 'MOD', 'PERCENTEQ': 'MOD_ASG', 'INSTANCEOF': 'TYPETEST'} -let s:opprecedences = {'notExpression': -1, 'noPrec': 0, 'assignPrec': 1, 'assignopPrec': 2, 'condPrec': 3, 'orPrec': 4, 'andPrec': 5, 'bitorPrec': 6, 'bitxorPrec': 7, 'bitandPrec': 8, 'eqPrec': 9, 'ordPrec': 10, 'shiftPrec': 11, 'addPrec': 12, 'mulPrec': 13, 'prefixPrec': 14, 'postfixPrec': 15, 'precCount': 16} - -fu! s:checkExprStat(t) - if a:t.tag =~# '^\(PREINC\|PREDEC\|POSTINC\|POSTDEC\|ASSIGN\|BITOR_ASG\|BITXOR_ASG\|BITAND_ASG\|SL_ASG\|SR_ASG\|USR_ASG\|PLUS_ASG\|MINUS_ASG\|MUL_ASG\|DIV_ASG\|MOD_ASG\|APPLY\|NEWCLASS\|ERRONEOUS\)$' - return a:t - else - call s:SyntaxError('not.stmt') - return {'tag': 'ERRONEOUS', 'pos': b:pos, 'errs': [a:t]} - endif -endfu - -fu! s:prec(token) - let oc = s:optag(a:token) - return oc == -1 ? -1 : s:opPrec(oc) -endfu - -fu! s:opPrec(tag) - if a:tag =~# '^\(POS\|NEG\|NOT\|COMPL\|PREINC\|PREDEC\)$' - return s:opprecedences.prefixPrec - elseif a:tag =~# '^\(POSTINC\|POSTDEC\|NULLCHK\)$' - return s:opprecedences.postfixPrec - elseif a:tag == 'ASSIGN' - return s:opprecedences.assignPrec - elseif a:tag =~# '^\(BITOR_ASG\|BITXOR_ASG\|BITAND_ASG\|SL_ASG\|SR_ASG\|USR_ASG\|PLUS_ASG\|MINUS_ASG\|MUL_ASG\|DIV_ASG\|MOD_ASG\)$' - return s:opprecedences.assignopPrec - elseif a:tag == 'OR' - return s:opprecedences.orPrec - elseif a:tag == 'AND' - return s:opprecedences.andPrec - elseif a:tag =~# '^\(EQ\|NE\)$' - return s:opprecedences.eqPrec - elseif a:tag =~# '^\(LT\|GT\|LE\|GE\)$' - return s:opprecedences.ordPrec - elseif a:tag == 'BITOR' - return s:opprecedences.bitorPrec - elseif a:tag == 'BITXOR' - return s:opprecedences.bitxorPrec - elseif a:tag == 'BITAND' - return s:opprecedences.bitandPrec - elseif a:tag =~# '^\(SL\|SR\|USR\)$' - return s:opprecedences.shiftPrec - elseif a:tag =~# '^\(PLUS\|MINUS\)$' - return s:opprecedences.addPrec - elseif a:tag =~# '^\(MUL\|DIV\|MOD\)$' - return s:opprecedences.mulPrec - elseif a:tag == 'TYPETEST' - return s:opprecedences.ordPrec - else - return -1 - endif -endfu - -fu! s:optag(token) - return get(s:MapToken2Tag, a:token, -1) -endfu - -fu! s:unoptag(token) - if a:token == 'PLUS' - return 'POS' - elseif a:token == 'SUB' - return 'NEG' - elseif a:token == 'BANG' - return 'NOT' - elseif a:token == 'TILDE' - return 'COMPL' - elseif a:token == 'PLUSPLUS' - return 'PREINC' - elseif a:token == 'SUBSUB' - return 'PREDEC' - else - return -1 - endif -endfu - -fu! s:typetag(token) - if a:token =~# '\(BYTE\|CHAR\|SHORT\|INT\|LONG\|FLOAT\|DOUBLE\|BOOLEAN\)' - return tolower(a:token) - else - return -1 - endif -endfu - -"}}}1 -" vim:set fdm=marker sw=2 nowrap: diff --git a/vim/autoload/javacomplete.vim b/vim/autoload/javacomplete.vim deleted file mode 100644 index ee55612..0000000 --- a/vim/autoload/javacomplete.vim +++ /dev/null @@ -1,2932 +0,0 @@ -" Vim completion script - hit 80% complete tasks -" Version: 0.77.1.2 -" Language: Java -" Maintainer: cheng fang -" Last Change: 2011-01-30 -" Copyright: Copyright (C) 2006-2007 cheng fang. All rights reserved. -" License: Vim License (see vim's :help license) - - -" constants {{{1 -" input context type -let s:CONTEXT_AFTER_DOT = 1 -let s:CONTEXT_METHOD_PARAM = 2 -let s:CONTEXT_IMPORT = 3 -let s:CONTEXT_IMPORT_STATIC = 4 -let s:CONTEXT_PACKAGE_DECL = 6 -let s:CONTEXT_NEED_TYPE = 7 -let s:CONTEXT_OTHER = 0 - - -let s:ARRAY_TYPE_MEMBERS = [ -\ {'kind': 'm', 'word': 'clone(', 'abbr': 'clone()', 'menu': 'Object clone()', }, -\ {'kind': 'm', 'word': 'equals(', 'abbr': 'equals()', 'menu': 'boolean equals(Object)', }, -\ {'kind': 'm', 'word': 'getClass(', 'abbr': 'getClass()', 'menu': 'Class Object.getClass()', }, -\ {'kind': 'm', 'word': 'hashCode(', 'abbr': 'hashCode()', 'menu': 'int hashCode()', }, -\ {'kind': 'f', 'word': 'length', 'menu': 'int'}, -\ {'kind': 'm', 'word': 'notify(', 'abbr': 'notify()', 'menu': 'void Object.notify()', }, -\ {'kind': 'm', 'word': 'notifyAll(', 'abbr': 'notifyAll()', 'menu': 'void Object.notifyAll()', }, -\ {'kind': 'm', 'word': 'toString(', 'abbr': 'toString()', 'menu': 'String toString()', }, -\ {'kind': 'm', 'word': 'wait(', 'abbr': 'wait()', 'menu': 'void Object.wait() throws InterruptedException', }, -\ {'kind': 'm', 'dup': 1, 'word': 'wait(', 'abbr': 'wait()', 'menu': 'void Object.wait(long timeout) throws InterruptedException', }, -\ {'kind': 'm', 'dup': 1, 'word': 'wait(', 'abbr': 'wait()', 'menu': 'void Object.wait(long timeout, int nanos) throws InterruptedException', }] - -let s:ARRAY_TYPE_INFO = {'tag': 'CLASSDEF', 'name': '[', 'ctors': [], -\ 'fields': [{'n': 'length', 'm': '1', 't': 'int'}], -\ 'methods':[ -\ {'n': 'clone', 'm': '1', 'r': 'Object', 'p': [], 'd': 'Object clone()'}, -\ {'n': 'equals', 'm': '1', 'r': 'boolean', 'p': ['Object'], 'd': 'boolean Object.equals(Object obj)'}, -\ {'n': 'getClass', 'm': '100010001', 'r': 'Class', 'p': [], 'd': 'Class Object.getClass()'}, -\ {'n': 'hashCode', 'm': '100000001', 'r': 'int', 'p': [], 'd': 'int Object.hashCode()'}, -\ {'n': 'notify', 'm': '100010001', 'r': 'void', 'p': [], 'd': 'void Object.notify()'}, -\ {'n': 'notifyAll','m': '100010001', 'r': 'void', 'p': [], 'd': 'void Object.notifyAll()'}, -\ {'n': 'toString', 'm': '1', 'r': 'String', 'p': [], 'd': 'String Object.toString()'}, -\ {'n': 'wait', 'm': '10001', 'r': 'void', 'p': [], 'd': 'void Object.wait() throws InterruptedException'}, -\ {'n': 'wait', 'm': '100010001', 'r': 'void', 'p': ['long'], 'd': 'void Object.wait(long timeout) throws InterruptedException'}, -\ {'n': 'wait', 'm': '10001', 'r': 'void', 'p': ['long','int'], 'd': 'void Object.wait(long timeout, int nanos) throws InterruptedException'}, -\ ]} - -let s:PRIMITIVE_TYPE_INFO = {'tag': 'CLASSDEF', 'name': '!', 'fields': [{'n': 'class','m': '1','t': 'Class'}]} - -let s:JSP_BUILTIN_OBJECTS = {'session': 'javax.servlet.http.HttpSession', -\ 'request': 'javax.servlet.http.HttpServletRequest', -\ 'response': 'javax.servlet.http.HttpServletResponse', -\ 'pageContext': 'javax.servlet.jsp.PageContext', -\ 'application': 'javax.servlet.ServletContext', -\ 'config': 'javax.servlet.ServletConfig', -\ 'out': 'javax.servlet.jsp.JspWriter', -\ 'page': 'javax.servlet.jsp.HttpJspPage', } - - -let s:PRIMITIVE_TYPES = ['boolean', 'byte', 'char', 'int', 'short', 'long', 'float', 'double'] -let s:KEYWORDS_MODS = ['public', 'private', 'protected', 'static', 'final', 'synchronized', 'volatile', 'transient', 'native', 'strictfp', 'abstract'] -let s:KEYWORDS_TYPE = ['class', 'interface', 'enum'] -let s:KEYWORDS = s:PRIMITIVE_TYPES + s:KEYWORDS_MODS + s:KEYWORDS_TYPE + ['super', 'this', 'void'] + ['assert', 'break', 'case', 'catch', 'const', 'continue', 'default', 'do', 'else', 'extends', 'finally', 'for', 'goto', 'if', 'implements', 'import', 'instanceof', 'interface', 'new', 'package', 'return', 'switch', 'throw', 'throws', 'try', 'while', 'true', 'false', 'null'] - -let s:PATH_SEP = ':' -let s:FILE_SEP = '/' -if has("win32") || has("win64") || has("win16") || has("dos32") || has("dos16") - let s:PATH_SEP = ';' - let s:FILE_SEP = '\' -endif - -let s:RE_BRACKETS = '\%(\s*\[\s*\]\)' -let s:RE_IDENTIFIER = '[a-zA-Z_$][a-zA-Z0-9_$]*' -let s:RE_QUALID = s:RE_IDENTIFIER. '\%(\s*\.\s*' .s:RE_IDENTIFIER. '\)*' - -let s:RE_REFERENCE_TYPE = s:RE_QUALID . s:RE_BRACKETS . '*' -let s:RE_TYPE = s:RE_REFERENCE_TYPE - -let s:RE_TYPE_ARGUMENT = '\%(?\s\+\%(extends\|super\)\s\+\)\=' . s:RE_TYPE -let s:RE_TYPE_ARGUMENTS = '<' . s:RE_TYPE_ARGUMENT . '\%(\s*,\s*' . s:RE_TYPE_ARGUMENT . '\)*>' -let s:RE_TYPE_WITH_ARGUMENTS_I = s:RE_IDENTIFIER . '\s*' . s:RE_TYPE_ARGUMENTS -let s:RE_TYPE_WITH_ARGUMENTS = s:RE_TYPE_WITH_ARGUMENTS_I . '\%(\s*' . s:RE_TYPE_WITH_ARGUMENTS_I . '\)*' - -let s:RE_TYPE_MODS = '\%(public\|protected\|private\|abstract\|static\|final\|strictfp\)' -let s:RE_TYPE_DECL_HEAD = '\(class\|interface\|enum\)[ \t\n\r ]\+' -let s:RE_TYPE_DECL = '\<\C\(\%(' .s:RE_TYPE_MODS. '\s\+\)*\)' .s:RE_TYPE_DECL_HEAD. '\(' .s:RE_IDENTIFIER. '\)[< \t\n\r ]' - -let s:RE_ARRAY_TYPE = '^\s*\(' .s:RE_QUALID . '\)\(' . s:RE_BRACKETS . '\+\)\s*$' -let s:RE_SELECT_OR_ACCESS = '^\s*\(' . s:RE_IDENTIFIER . '\)\s*\(\[.*\]\)\=\s*$' -let s:RE_ARRAY_ACCESS = '^\s*\(' . s:RE_IDENTIFIER . '\)\s*\(\[.*\]\)\+\s*$' -let s:RE_CASTING = '^\s*(\(' .s:RE_QUALID. '\))\s*\(' . s:RE_IDENTIFIER . '\)\>' - -let s:RE_KEYWORDS = '\<\%(' . join(s:KEYWORDS, '\|') . '\)\>' - - -" local variables {{{1 -let b:context_type = s:CONTEXT_OTHER -"let b:statement = '' " statement before cursor -let b:dotexpr = '' " expression ends with '.' -let b:incomplete = '' " incomplete word: 1. dotexpr.method(|) 2. new classname(|) 3. dotexpr.ab|, 4. ja|, 5. method(| -let b:errormsg = '' - -" script variables {{{1 -let s:cache = {} " FQN -> member list, e.g. {'java.lang.StringBuffer': classinfo, 'java.util': packageinfo, '/dir/TopLevelClass.java': compilationUnit} -let s:files = {} " srouce file path -> properties, e.g. {filekey: {'unit': compilationUnit, 'changedtick': tick, }} -let s:history = {} " - - -" This function is used for the 'omnifunc' option. {{{1 -function! javacomplete#Complete(findstart, base) - if a:findstart - let s:et_whole = reltime() - let start = col('.') - 1 - let s:log = [] - - " reset enviroment - let b:dotexpr = '' - let b:incomplete = '' - let b:context_type = s:CONTEXT_OTHER - - let statement = s:GetStatement() - call s:WatchVariant('statement: "' . statement . '"') - - if statement =~ '[.0-9A-Za-z_]\s*$' - let valid = 1 - if statement =~ '\.\s*$' - let valid = statement =~ '[")0-9A-Za-z_\]]\s*\.\s*$' && statement !~ '\<\H\w\+\.\s*$' && statement !~ '\<\(abstract\|assert\|break\|case\|catch\|const\|continue\|default\|do\|else\|enum\|extends\|final\|finally\|for\|goto\|if\|implements\|import\|instanceof\|interface\|native\|new\|package\|private\|protected\|public\|return\|static\|strictfp\|switch\|synchronized\|throw\|throws\|transient\|try\|volatile\|while\|true\|false\|null\)\.\s*$' - endif - if !valid - return -1 - endif - - let b:context_type = s:CONTEXT_AFTER_DOT - - " import or package declaration - if statement =~# '^\s*\(import\|package\)\s\+' - let statement = substitute(statement, '\s\+\.', '.', 'g') - let statement = substitute(statement, '\.\s\+', '.', 'g') - if statement =~ '^\s*import\s\+' - let b:context_type = statement =~# '\ 0 - " filter according to b:incomplete - if len(b:incomplete) > 0 && b:incomplete != '+' - let result = filter(result, "type(v:val) == type('') ? v:val =~ '^" . b:incomplete . "' : v:val['word'] =~ '^" . b:incomplete . "'") - endif - - if exists('s:padding') && !empty(s:padding) - for item in result - if type(item) == type("") - let item .= s:padding - else - let item.word .= s:padding - endif - endfor - unlet s:padding - endif - - call s:Debug('finish completion' . reltimestr(reltime(s:et_whole)) . 's') - return result - endif - - if strlen(b:errormsg) > 0 - echoerr 'javacomplete error: ' . b:errormsg - let b:errormsg = '' - endif -endfunction - -" Precondition: incomplete must be a word without '.'. -" return all the matched, variables, fields, methods, types, packages -fu! s:CompleteAfterWord(incomplete) - " packages in jar files - if !exists('s:all_packages_in_jars_loaded') - call s:DoGetInfoByReflection('-', '-P') - let s:all_packages_in_jars_loaded = 1 - endif - - let pkgs = [] - let types = [] - for key in keys(s:cache) - if key =~# '^' . a:incomplete - if type(s:cache[key]) == type('') || get(s:cache[key], 'tag', '') == 'PACKAGE' - call add(pkgs, {'kind': 'P', 'word': key}) - - " filter out type info - elseif b:context_type != s:CONTEXT_PACKAGE_DECL && b:context_type != s:CONTEXT_IMPORT && b:context_type != s:CONTEXT_IMPORT_STATIC - call add(types, {'kind': 'C', 'word': key}) - endif - endif - endfor - - let pkgs += s:DoGetPackageInfoInDirs(a:incomplete, b:context_type == s:CONTEXT_PACKAGE_DECL, 1) - - - " add accessible types which name beginning with the incomplete in source files - " TODO: remove the inaccessible - if b:context_type != s:CONTEXT_PACKAGE_DECL - " single type import - for fqn in s:GetImports('imports_fqn') - let name = fqn[strridx(fqn, ".")+1:] - if name =~ '^' . a:incomplete - call add(types, {'kind': 'C', 'word': name}) - endif - endfor - - " current file - let lnum_old = line('.') - let col_old = col('.') - call cursor(1, 1) - while 1 - let lnum = search('\<\C\(class\|interface\|enum\)[ \t\n\r ]\+' . a:incomplete . '[a-zA-Z0-9_$]*[< \t\n\r ]', 'W') - if lnum == 0 - break - elseif s:InCommentOrLiteral(line('.'), col('.')) - continue - else - normal w - call add(types, {'kind': 'C', 'word': matchstr(getline(line('.'))[col('.')-1:], s:RE_IDENTIFIER)}) - endif - endwhile - call cursor(lnum_old, col_old) - - " other files - let filepatterns = '' - for dirpath in s:GetSourceDirs(expand('%:p')) - let filepatterns .= escape(dirpath, ' \') . '/*.java ' - endfor - exe 'vimgrep /\s*' . s:RE_TYPE_DECL . '/jg ' . filepatterns - for item in getqflist() - if item.text !~ '^\s*\*\s\+' - let text = matchstr(s:Prune(item.text, -1), '\s*' . s:RE_TYPE_DECL) - if text != '' - let subs = split(substitute(text, '\s*' . s:RE_TYPE_DECL, '\1;\2;\3', ''), ';', 1) - if subs[2] =~# '^' . a:incomplete && (subs[0] =~ '\C\' || fnamemodify(bufname(item.bufnr), ':p:h') == expand('%:p:h')) - call add(types, {'kind': 'C', 'word': subs[2]}) - endif - endif - endif - endfor - endif - - - let result = [] - - " add variables and members in source files - if b:context_type == s:CONTEXT_AFTER_DOT - let matches = s:SearchForName(a:incomplete, 0, 0) - let result += sort(eval('[' . s:DoGetFieldList(matches[2]) . ']')) - let result += sort(eval('[' . s:DoGetMethodList(matches[1]) . ']')) - endif - let result += sort(pkgs) - let result += sort(types) - - return result -endfu - - -" Precondition: expr must end with '.' -" return members of the value of expression -function! s:CompleteAfterDot(expr) - let items = s:ParseExpr(a:expr) " TODO: return a dict containing more than items - if empty(items) - return [] - endif - - - " 0. String literal - call s:Info('P0. "str".|') - if items[-1] =~ '"$' - return s:GetMemberList("java.lang.String") - endif - - - let ti = {} - let ii = 1 " item index - let itemkind = 0 - - " - " optimized process - " - " search the longest expr consisting of ident - let i = 1 - let k = i - while i < len(items) && items[i] =~ '^\s*' . s:RE_IDENTIFIER . '\s*$' - let ident = substitute(items[i], '\s', '', 'g') - if ident == 'class' || ident == 'this' || ident == 'super' - let k = i - " return when found other keywords - elseif s:IsKeyword(ident) - return [] - endif - let items[i] = substitute(items[i], '\s', '', 'g') - let i += 1 - endwhile - - if i > 1 - " cases: "this.|", "super.|", "ClassName.this.|", "ClassName.super.|", "TypeName.class.|" - if items[k] ==# 'class' || items[k] ==# 'this' || items[k] ==# 'super' - call s:Info('O1. ' . items[k] . ' ' . join(items[:k-1], '.')) - let ti = s:DoGetClassInfo(items[k] == 'class' ? 'java.lang.Class' : join(items[:k-1], '.')) - if !empty(ti) - let itemkind = items[k] ==# 'this' ? 1 : items[k] ==# 'super' ? 2 : 0 - let ii = k+1 - else - return [] - endif - - " case: "java.io.File.|" - else - let fqn = join(items[:i-1], '.') - let srcpath = join(s:GetSourceDirs(expand('%:p'), s:GetPackageName()), ',') - call s:Info('O2. ' . fqn) - call s:DoGetTypeInfoForFQN([fqn], srcpath) - if get(get(s:cache, fqn, {}), 'tag', '') == 'CLASSDEF' - let ti = s:cache[fqn] - let itemkind = 11 - let ii = i - endif - endif - endif - - - " - " first item - " - if empty(ti) - " cases: - " 1) "int.|", "void.|" - primitive type or pseudo-type, return `class` - " 2) "this.|", "super.|" - special reference - " 3) "var.|" - variable or field - " 4) "String.|" - type imported or defined locally - " 5) "java.|" - package - if items[0] =~ '^\s*' . s:RE_IDENTIFIER . '\s*$' - let ident = substitute(items[0], '\s', '', 'g') - - if s:IsKeyword(ident) - " 1) - call s:Info('F1. "' . ident . '.|"') - if ident ==# 'void' || s:IsBuiltinType(ident) - let ti = s:PRIMITIVE_TYPE_INFO - let itemkind = 11 - - " 2) - call s:Info('F2. "' . ident . '.|"') - elseif ident ==# 'this' || ident ==# 'super' - let itemkind = ident ==# 'this' ? 1 : ident ==# 'super' ? 2 : 0 - let ti = s:DoGetClassInfo(ident) - endif - - else - " 3) - let typename = s:GetDeclaredClassName(ident) - call s:Info('F3. "' . ident . '.|" typename: "' . typename . '"') - if (typename != '') - if typename[0] == '[' || typename[-1:] == ']' - let ti = s:ARRAY_TYPE_INFO - elseif typename != 'void' && !s:IsBuiltinType(typename) - let ti = s:DoGetClassInfo(typename) - endif - - else - " 4) - call s:Info('F4. "TypeName.|"') - let ti = s:DoGetClassInfo(ident) - let itemkind = 11 - - if get(ti, 'tag', '') != 'CLASSDEF' - let ti = {} - endif - - " 5) - if empty(ti) - call s:Info('F5. "package.|"') - unlet ti - let ti = s:GetMembers(ident) " s:DoGetPackegInfo(ident) - let itemkind = 20 - endif - endif - endif - - " method invocation: "method().|" - "this.method().|" - elseif items[0] =~ '^\s*' . s:RE_IDENTIFIER . '\s*(' - let ti = s:MethodInvocation(items[0], ti, itemkind) - - " array type, return `class`: "int[] [].|", "java.lang.String[].|", "NestedClass[].|" - elseif items[0] =~# s:RE_ARRAY_TYPE - call s:Info('array type. "' . items[0] . '"') - let qid = substitute(items[0], s:RE_ARRAY_TYPE, '\1', '') - if s:IsBuiltinType(qid) || (!s:HasKeyword(qid) && !empty(s:DoGetClassInfo(qid))) - let ti = s:PRIMITIVE_TYPE_INFO - let itemkind = 11 - endif - - " class instance creation expr: "new String().|", "new NonLoadableClass().|" - " array creation expr: "new int[i=1] [val()].|", "new java.lang.String[].|" - elseif items[0] =~ '^\s*new\s\+' - call s:Info('creation expr. "' . items[0] . '"') - let subs = split(substitute(items[0], '^\s*new\s\+\(' .s:RE_QUALID. '\)\s*\([([]\)', '\1;\2', ''), ';') - if subs[1][0] == '[' - let ti = s:ARRAY_TYPE_INFO - elseif subs[1][0] == '(' - let ti = s:DoGetClassInfo(subs[0]) - " exclude interfaces and abstract class. TODO: exclude the inaccessible - if get(ti, 'flags', '')[-10:-10] || get(ti, 'flags', '')[-11:-11] - echo 'cannot instantiate the type ' . subs[0] - let ti = {} - return [] - endif - endif - - " casting conversion: "(Object)o.|" - elseif items[0] =~ s:RE_CASTING - call s:Info('Casting conversion. "' . items[0] . '"') - let subs = split(substitute(items[0], s:RE_CASTING, '\1;\2', ''), ';') - let ti = s:DoGetClassInfo(subs[0]) - - " array access: "var[i][j].|" Note: "var[i][]" is incorrect - elseif items[0] =~# s:RE_ARRAY_ACCESS - let subs = split(substitute(items[0], s:RE_ARRAY_ACCESS, '\1;\2', ''), ';') - if get(subs, 1, '') !~ s:RE_BRACKETS - let typename = s:GetDeclaredClassName(subs[0]) - call s:Info('ArrayAccess. "' .items[0]. '.|" typename: "' . typename . '"') - if (typename != '') - let ti = s:ArrayAccess(typename, items[0]) - endif - endif - endif - endif - - - " - " next items - " - while !empty(ti) && ii < len(items) - " method invocation: "PrimaryExpr.method(parameters)[].|" - if items[ii] =~ '^\s*' . s:RE_IDENTIFIER . '\s*(' - let ti = s:MethodInvocation(items[ii], ti, itemkind) - let itemkind = 0 - let ii += 1 - continue - - - " expression of selection, field access, array access - elseif items[ii] =~ s:RE_SELECT_OR_ACCESS - let subs = split(substitute(items[ii], s:RE_SELECT_OR_ACCESS, '\1;\2', ''), ';') - let ident = subs[0] - let brackets = get(subs, 1, '') - - " package members - if itemkind/10 == 2 && empty(brackets) && !s:IsKeyword(ident) - let qn = join(items[:ii], '.') - if type(ti) == type([]) - let idx = s:Index(ti, ident, 'word') - if idx >= 0 - if ti[idx].kind == 'P' - unlet ti - let ti = s:GetMembers(qn) - let ii += 1 - continue - elseif ti[idx].kind == 'C' - unlet ti - let ti = s:DoGetClassInfo(qn) - let itemkind = 11 - let ii += 1 - continue - endif - endif - endif - - - " type members - elseif itemkind/10 == 1 && empty(brackets) - if ident ==# 'class' || ident ==# 'this' || ident ==# 'super' - let ti = s:DoGetClassInfo(ident == 'class' ? 'java.lang.Class' : join(items[:ii-1], '.')) - let itemkind = ident ==# 'this' ? 1 : ident ==# 'super' ? 2 : 0 - let ii += 1 - continue - - elseif !s:IsKeyword(ident) && type(ti) == type({}) && get(ti, 'tag', '') == 'CLASSDEF' - " accessible static field - "let idx = s:Index(get(ti, 'fields', []), ident, 'n') - "if idx >= 0 && s:IsStatic(ti.fields[idx].m) - " let ti = s:ArrayAccess(ti.fields[idx].t, items[ii]) - let members = s:SearchMember(ti, ident, 1, itemkind, 1, 0) - if !empty(members[2]) - let ti = s:ArrayAccess(members[2][0].t, items[ii]) - let itemkind = 0 - let ii += 1 - continue - endif - - " accessible nested type - "if !empty(filter(copy(get(ti, 'classes', [])), 'strpart(v:val, strridx(v:val, ".")) ==# "' . ident . '"')) - if !empty(members[0]) - let ti = s:DoGetClassInfo(join(items[:ii], '.')) - let ii += 1 - continue - endif - endif - - - " instance members - elseif itemkind/10 == 0 && !s:IsKeyword(ident) - if type(ti) == type({}) && get(ti, 'tag', '') == 'CLASSDEF' - "let idx = s:Index(get(ti, 'fields', []), ident, 'n') - "if idx >= 0 - " let ti = s:ArrayAccess(ti.fields[idx].t, items[ii]) - let members = s:SearchMember(ti, ident, 1, itemkind, 1, 0) - let itemkind = 0 - if !empty(members[2]) - let ti = s:ArrayAccess(members[2][0].t, items[ii]) - let ii += 1 - continue - endif - endif - endif - endif - - return [] - endwhile - - - " type info or package info --> members - if !empty(ti) - if type(ti) == type({}) - if get(ti, 'tag', '') == 'CLASSDEF' - if get(ti, 'name', '') == '!' - return [{'kind': 'f', 'word': 'class', 'menu': 'Class'}] - elseif get(ti, 'name', '') == '[' - return s:ARRAY_TYPE_MEMBERS - elseif itemkind < 20 - return s:DoGetMemberList(ti, itemkind) - endif - elseif get(ti, 'tag', '') == 'PACKAGE' - " TODO: ti -> members, in addition to packages in dirs - return s:GetMembers( substitute(join(items, '.'), '\s', '', 'g') ) - endif - elseif type(ti) == type([]) - return ti - endif - endif - - return [] -endfunction - - -fu! s:MethodInvocation(expr, ti, itemkind) - let subs = split(substitute(a:expr, '\s*\(' . s:RE_IDENTIFIER . '\)\s*\((.*\)', '\1;\2', ''), ';') - - " all methods matched - if empty(a:ti) - let methods = s:SearchForName(subs[0], 0, 1)[1] - elseif type(a:ti) == type({}) && get(a:ti, 'tag', '') == 'CLASSDEF' - let methods = s:SearchMember(a:ti, subs[0], 1, a:itemkind, 1, 0, a:itemkind == 2)[1] -" let methods = s:filter(get(a:ti, 'methods', []), 'item.n == "' . subs[0] . '"') -" if a:itemkind == 1 || a:itemkind == 2 -" let methods += s:filter(get(a:ti, 'declared_methods', []), 'item.n == "' . subs[0] . '"') -" endif - else - let methods = [] - endif - - let method = s:DetermineMethod(methods, subs[1]) - if !empty(method) - return s:ArrayAccess(method.r, a:expr) - endif - return {} -endfu - -fu! s:ArrayAccess(arraytype, expr) - if a:expr =~ s:RE_BRACKETS | return {} | endif - let typename = a:arraytype - - let dims = 0 - if typename[0] == '[' || typename[-1:] == ']' || a:expr[-1:] == ']' - let dims = s:CountDims(a:expr) - s:CountDims(typename) - if dims == 0 - let typename = matchstr(typename, s:RE_IDENTIFIER) - elseif dims < 0 - return s:ARRAY_TYPE_INFO - else - "echoerr 'dims exceeds' - endif - endif - if dims == 0 - if typename != 'void' && !s:IsBuiltinType(typename) - return s:DoGetClassInfo(typename) - endif - endif - return {} -endfu - - -" Quick information {{{1 -function! MyBalloonExpr() - if (searchdecl(v:beval_text, 1, 0) == 0) - return s:GetVariableDeclaration() - endif - return '' -" return 'Cursor is at line ' . v:beval_lnum . -" \', column ' . v:beval_col . -" \ ' of file ' . bufname(v:beval_bufnr) . -" \ ' on word "' . v:beval_text . '"' -endfunction -"set bexpr=MyBalloonExpr() -"set ballooneval - -" parameters information {{{1 -fu! javacomplete#CompleteParamsInfo(findstart, base) - if a:findstart - return col('.') - 1 - endif - - - let mi = s:GetMethodInvocationExpr(s:GetStatement()) - if empty(mi.method) - return [] - endif - - " TODO: how to determine overloaded functions - "let mi.params = s:EvalParams(mi.params) - if empty(mi.expr) - let methods = s:SearchForName(mi.method, 0, 1)[1] - let result = eval('[' . s:DoGetMethodList(methods) . ']') - elseif mi.method == '+' - let result = s:GetConstructorList(mi.expr) - else - let result = s:CompleteAfterDot(mi.expr) - endif - - if !empty(result) - if !empty(mi.method) && mi.method != '+' - let result = filter(result, "type(v:val) == type('') ? v:val ==# '" . mi.method . "' : v:val['word'] ==# '" . mi.method . "('") - endif - return result - endif -endfu - -" scanning and parsing {{{1 - -" Search back from the cursor position till meeting '{' or ';'. -" '{' means statement start, ';' means end of a previous statement. -" Return: statement before cursor -" Note: It's the base for parsing. And It's OK for most cases. -function! s:GetStatement() - if getline('.') =~ '^\s*\(import\|package\)\s\+' - return strpart(getline('.'), match(getline('.'), '\(import\|package\)'), col('.')-1) - endif - - let lnum_old = line('.') - let col_old = col('.') - - while 1 - if search('[{};]\|<%\|<%!', 'bW') == 0 - let lnum = 1 - let col = 1 - else - if s:InCommentOrLiteral(line('.'), col('.')) - continue - endif - - normal w - let lnum = line('.') - let col = col('.') - endif - break - endwhile - - silent call cursor(lnum_old, col_old) - return s:MergeLines(lnum, col, lnum_old, col_old) -endfunction - -fu! s:MergeLines(lnum, col, lnum_old, col_old) - let lnum = a:lnum - let col = a:col - - let str = '' - if lnum < a:lnum_old - let str = s:Prune(strpart(getline(lnum), a:col-1)) - let lnum += 1 - while lnum < a:lnum_old - let str .= s:Prune(getline(lnum)) - let lnum += 1 - endwhile - let col = 1 - endif - let lastline = strpart(getline(a:lnum_old), col-1, a:col_old-col) - let str .= s:Prune(lastline, col) - let str = s:RemoveBlockComments(str) - " generic in JAVA 5+ - while match(str, s:RE_TYPE_ARGUMENTS) != -1 - let str = substitute(str, '\(' . s:RE_TYPE_ARGUMENTS . '\)', '\=repeat(" ", len(submatch(1)))', 'g') - endwhile - let str = substitute(str, '\s\s\+', ' ', 'g') - let str = substitute(str, '\([.()]\)[ \t]\+', '\1', 'g') - let str = substitute(str, '[ \t]\+\([.()]\)', '\1', 'g') - return s:Trim(str) . matchstr(lastline, '\s*$') -endfu - -" Extract a clean expr, removing some non-necessary characters. -fu! s:ExtractCleanExpr(expr) - let cmd = substitute(a:expr, '[ \t\r\n ]\+\([.()[\]]\)', '\1', 'g') - let cmd = substitute(cmd, '\([.()[\]]\)[ \t\r\n ]\+', '\1', 'g') - - let pos = strlen(cmd)-1 - while pos >= 0 && cmd[pos] =~ '[a-zA-Z0-9_.)\]]' - if cmd[pos] == ')' - let pos = s:SearchPairBackward(cmd, pos, '(', ')') - elseif cmd[pos] == ']' - let pos = s:SearchPairBackward(cmd, pos, '[', ']') - endif - let pos -= 1 - endwhile - - " try looking back for "new" - let idx = match(strpart(cmd, 0, pos+1), '\= 0 - if a:expr[e] == '.' - let subexpr = strpart(a:expr, s, e-s) - call extend(items, isparen ? s:ProcessParentheses(subexpr) : [subexpr]) - let isparen = 0 - let s = e + 1 - elseif a:expr[e] == '(' - let e = s:GetMatchedIndexEx(a:expr, e, '(', ')') - let isparen = 1 - if e < 0 - break - else - let e = matchend(a:expr, '^\s*[.[]', e+1)-1 - continue - endif - elseif a:expr[e] == '[' - let e = s:GetMatchedIndexEx(a:expr, e, '[', ']') - if e < 0 - break - else - let e = matchend(a:expr, '^\s*[.[]', e+1)-1 - continue - endif - endif - let e = match(a:expr, '[.([]', s) - endwhile - let tail = strpart(a:expr, s) - if tail !~ '^\s*$' - call extend(items, isparen ? s:ProcessParentheses(tail) : [tail]) - endif - - return items -endfu - -" Given optional argument, call s:ParseExpr() to parser the nonparentheses expr -fu! s:ProcessParentheses(expr, ...) - let s = matchend(a:expr, '^\s*(') - if s != -1 - let e = s:GetMatchedIndexEx(a:expr, s-1, '(', ')') - if e >= 0 - let tail = strpart(a:expr, e+1) - if tail =~ '^\s*[\=$' - return s:ProcessParentheses(strpart(a:expr, s, e-s), 1) - elseif tail =~ '^\s*\w' - return [strpart(a:expr, 0, e+1) . 'obj.'] - endif - endif - - " multi-dot-expr except for new expr - elseif a:0 > 0 && stridx(a:expr, '.') != match(a:expr, '\.\s*$') && a:expr !~ '^\s*new\s\+' - return s:ParseExpr(a:expr) - endif - return [a:expr] -endfu - -" return {'expr': , 'method': , 'params': } -fu! s:GetMethodInvocationExpr(expr) - let idx = strlen(a:expr)-1 - while idx >= 0 - if a:expr[idx] == '(' - break - elseif a:expr[idx] == ')' - let idx = s:SearchPairBackward(a:expr, idx, '(', ')') - elseif a:expr[idx] == ']' - let idx = s:SearchPairBackward(a:expr, idx, '[', ']') - endif - let idx -= 1 - endwhile - - let mi = {'expr': strpart(a:expr, 0, idx+1), 'method': '', 'params': strpart(a:expr, idx+1)} - let idx = match(mi.expr, '\= 0 - let mi.method = '+' - let mi.expr = substitute(matchstr(strpart(mi.expr, idx+4), s:RE_QUALID), '\s', '', 'g') - else - let idx = match(mi.expr, '\<' . s:RE_IDENTIFIER . '\s*(\s*$') - if idx >= 0 - let subs = s:SplitAt(mi.expr, idx-1) - let mi.method = substitute(subs[1], '\s*(\s*$', '', '') - let mi.expr = s:ExtractCleanExpr(subs[0]) - endif - endif - return mi -endfu - -" imports {{{1 -function! s:GenerateImports() - let imports = [] - - let lnum_old = line('.') - let col_old = col('.') - call cursor(1, 1) - - if &ft == 'jsp' - while 1 - let lnum = search('\' || str =~ '' - let str = substitute(str, '.*import=[''"]\([a-zA-Z0-9_$.*, \t]\+\)[''"].*', '\1', '') - for item in split(str, ',') - call add(imports, substitute(item, '\s', '', 'g')) - endfor - endif - endwhile - else - while 1 - let lnum = search('\', 'W') - if (lnum == 0) - break - elseif !s:InComment(line("."), col(".")-1) - normal w - " TODO: search semicolon or import keyword, excluding comment - let stat = matchstr(getline(lnum)[col('.')-1:], '\(static\s\+\)\?\(' .s:RE_QUALID. '\%(\s*\.\s*\*\)\?\)\s*;') - if !empty(stat) - call add(imports, stat[:-2]) - endif - endif - endwhile - endif - - call cursor(lnum_old, col_old) - return imports -endfunction - -fu! s:GetImports(kind, ...) - let filekey = a:0 > 0 && !empty(a:1) ? a:1 : s:GetCurrentFileKey() - let props = get(s:files, filekey, {}) - if !has_key(props, a:kind) - let props['imports'] = filekey == s:GetCurrentFileKey() ? s:GenerateImports() : props.unit.imports - let props['imports_static'] = [] - let props['imports_fqn'] = [] - let props['imports_star'] = ['java.lang.'] - if &ft == 'jsp' || filekey =~ '\.jsp$' - let props.imports_star += ['javax.servlet.', 'javax.servlet.http.', 'javax.servlet.jsp.'] - endif - - for import in props.imports - let subs = split(substitute(import, '^\s*\(static\s\+\)\?\(' .s:RE_QUALID. '\%(\s*\.\s*\*\)\?\)\s*$', '\1;\2', ''), ';', 1) - let qid = substitute(subs[1] , '\s', '', 'g') - if !empty(subs[0]) - call add(props.imports_static, qid) - elseif qid[-1:] == '*' - call add(props.imports_star, qid[:-2]) - else - call add(props.imports_fqn, qid) - endif - endfor - let s:files[filekey] = props - endif - return get(props, a:kind, []) -endfu - -" search for name in -" return the fqn matched -fu! s:SearchSingleTypeImport(name, fqns) - let matches = s:filter(a:fqns, 'item =~# ''\<' . a:name . '$''') - if len(matches) == 1 - return matches[0] - elseif !empty(matches) - echoerr 'Name "' . a:name . '" conflicts between ' . join(matches, ' and ') - return matches[0] - endif - return '' -endfu - -" search for name in static imports, return list of members with the same name -" return [types, methods, fields] -fu! s:SearchStaticImports(name, fullmatch) - let result = [[], [], []] - let candidates = [] " list of the canonical name - for item in s:GetImports('imports_static') - if item[-1:] == '*' " static import on demand - call add(candidates, item[:-3]) - elseif item[strridx(item, '.')+1:] ==# a:name - \ || (!a:fullmatch && item[strridx(item, '.')+1:] =~ '^' . a:name) - call add(candidates, item[:strridx(item, '.')]) - endif - endfor - if empty(candidates) - return result - endif - - - " read type info which are not in cache - let commalist = '' - for typename in candidates - if !has_key(s:cache, typename) - let commalist .= typename . ',' - endif - endfor - if commalist != '' - let res = s:RunReflection('-E', commalist, 's:SearchStaticImports in Batch') - if res =~ "^{'" - let dict = eval(res) - for key in keys(dict) - let s:cache[key] = s:Sort(dict[key]) - endfor - endif - endif - - " search in all candidates - for typename in candidates - let ti = get(s:cache, typename, 0) - if type(ti) == type({}) && get(ti, 'tag', '') == 'CLASSDEF' - let members = s:SearchMember(ti, a:name, a:fullmatch, 12, 1, 0) - let result[1] += members[1] - let result[2] += members[2] - "let pattern = 'item.n ' . (a:fullmatch ? '==# ''' : '=~# ''^') . a:name . ''' && s:IsStatic(item.m)' - "let result[1] += s:filter(get(ti, 'methods', []), pattern) - "let result[2] += s:filter(get(ti, 'fields', []), pattern) - else - " TODO: mark the wrong import declaration. - endif - endfor - return result -endfu - - -" search decl {{{1 -" Return: The declaration of identifier under the cursor -" Note: The type of a variable must be imported or a fqn. -function! s:GetVariableDeclaration() - let lnum_old = line('.') - let col_old = col('.') - - silent call search('[^a-zA-Z0-9$_.,?<>[\] \t\r\n ]', 'bW') " call search('[{};(,]', 'b') - normal w - let lnum = line('.') - let col = col('.') - if (lnum == lnum_old && col == col_old) - return '' - endif - -" silent call search('[;){]') -" let lnum_end = line('.') -" let col_end = col('.') -" let declaration = '' -" while (lnum <= lnum_end) -" let declaration = declaration . getline(lnum) -" let lnum = lnum + 1 -" endwhile -" let declaration = strpart(declaration, col-1) -" let declaration = substitute(declaration, '\.[ \t]\+', '.', 'g') - - silent call cursor(lnum_old, col_old) - return s:MergeLines(lnum, col, lnum_old, col_old) -endfunction - -function! s:FoundClassDeclaration(type) - let lnum_old = line('.') - let col_old = col('.') - call cursor(1, 1) - while 1 - let lnum = search('\<\C\(class\|interface\|enum\)[ \t\n\r ]\+' . a:type . '[< \t\n\r ]', 'W') - if lnum == 0 || !s:InCommentOrLiteral(line('.'), col('.')) - break - endif - endwhile - - " search mainly for the cases: " class /* block comment */ Ident" - " " class // comment \n Ident " - if lnum == 0 - let found = 0 - while !found - let lnum = search('\<\C\(class\|interface\|enum\)[ \t\n\r ]\+', 'W') - if lnum == 0 - break - elseif s:InCommentOrLiteral(line('.'), col('.')) - continue - else - normal w - " skip empty line - while getline(line('.'))[col('.')-1] == '' - normal w - endwhile - let lnum = line('.') - let col = col('.') - while 1 - if match(getline(lnum)[col-1:], '^[ \t\n\r ]*' . a:type . '[< \t\n\r ]') >= 0 - let found = 1 - " meets comment - elseif match(getline(lnum)[col-1:], '^[ \t\n\r ]*\(//\|/\*\)') >= 0 - if getline(lnum)[col-1:col] == '//' - normal $eb - else - let lnum = search('\*\/', 'W') - if lnum == 0 - break - endif - normal web - endif - let lnum = line('.') - let col = col('.') - continue - endif - break - endwhile - endif - endwhile - endif - - silent call cursor(lnum_old, col_old) - return lnum -endfu - -fu! s:FoundClassLocally(type) - " current path - if globpath(expand('%:p:h'), a:type . '.java') != '' - return 1 - endif - - " - let srcpath = javacomplete#GetSourcePath(1) - let file = globpath(srcpath, substitute(fqn, '\.', '/', 'g') . '.java') - if file != '' - return 1 - endif - - return 0 -endfu - -" regexp samples: -" echo search('\(\(public\|protected|private\)[ \t\n\r]\+\)\?\(\(static\)[ \t\n\r]\+\)\?\(\\|\\)[ \t\n\r]\+HelloWorld[^a-zA-Z0-9_$]', 'W') -" echo substitute(getline('.'), '.*\(\(public\|protected\|private\)[ \t\n\r]\+\)\?\(\(static\)[ \t\n\r]\+\)\?\(\\|\\)\s\+\([a-zA-Z0-9_]\+\)\s\+\(\(implements\|extends\)\s\+\([^{]\+\)\)\?\s*{.*', '["\1", "\2", "\3", "\4", "\5", "\6", "\8", "\9"]', '') -" code sample: -function! s:GetClassDeclarationOf(type) - call cursor(1, 1) - let decl = [] - - let lnum = search('\(\\|\\)[ \t\n\r]\+' . a:type . '[^a-zA-Z0-9_$]', 'W') - if (lnum != 0) - " TODO: search back for optional 'public | private' and 'static' - " join lines till to '{' - let lnum_end = search('{') - if (lnum_end != 0) - let str = '' - while (lnum <= lnum_end) - let str = str . getline(lnum) - let lnum = lnum + 1 - endwhile - - exe "let decl = " . substitute(str, '.*\(\\|\\)\s\+\([a-zA-Z0-9_]\+\)\s\+\(\(implements\|extends\)\s\+\([^{]\+\)\)\?\s*{.*', '["\1", "\2", "\4", "\5"]', '') - endif - endif - - return decl -endfunction - -" return list -" 0 class | interface -" 1 name -" [2 implements | extends ] -" [3 parent list ] -function! s:GetThisClassDeclaration() - let lnum_old = line('.') - let col_old = col('.') - - while (1) - call search('\(\\|\\|\\)[ \t\r\n]\+', 'bW') - if !s:InComment(line("."), col(".")-1) - if getline('.')[col('.')-2] !~ '\S' - break - endif - end - endwhile - - " join lines till to '{' - let str = '' - let lnum = line('.') - call search('{') - let lnum_end = line('.') - while (lnum <= lnum_end) - let str = str . getline(lnum) - let lnum = lnum + 1 - endwhile - - - let declaration = substitute(str, '.*\(\\|\\)\s\+\([a-zA-Z0-9_]\+\)\(\s\+\(implements\|extends\)\s\+\([^{]\+\)\)\?\s*{.*', '["\1", "\2", "\4", "\5"]', '') - call cursor(lnum_old, col_old) - if declaration !~ '^[' - echoerr 'Some error occurs when recognizing this class:' . declaration - return ['', ''] - endif - exe "let list = " . declaration - return list -endfunction - -" searches for name of a var or a field and determines the meaning {{{1 - -" The standard search order of a variable or field is as follows: -" 1. Local variables declared in the code block, for loop, or catch clause -" from current scope up to the most outer block, a method or an initialization block -" 2. Parameters if the code is in a method or ctor -" 3. Fields of the type -" 4. Accessible inherited fields. -" 5. If the type is a nested type, -" local variables of the enclosing block or fields of the enclosing class. -" Note that if the type is a static nested type, only static members of an enclosing block or class are searched -" Reapply this rule to the upper block and class enclosing the enclosing type recursively -" 6. Accessible static fields imported. -" It is allowed that several fields with the same name. - -" The standard search order of a method is as follows: -" 1. Methods of the type -" 2. Accessible inherited methods. -" 3. Methods of the enclosing class if the type is a nested type. -" 4. Accessible static methods imported. -" It is allowed that several methods with the same name and signature. - -" first return at once if found one. -" fullmatch 1 - equal, 0 - match beginning -" return [types, methods, fields, vars] -fu! s:SearchForName(name, first, fullmatch) - let result = [[], [], [], []] - if s:IsKeyword(a:name) - return result - endif - - " use java_parser.vim - if javacomplete#GetSearchdeclMethod() == 4 - " declared in current file - let unit = javacomplete#parse() - let targetPos = java_parser#MakePos(line('.')-1, col('.')-1) - let trees = s:SearchNameInAST(unit, a:name, targetPos, a:fullmatch) - for tree in trees - if tree.tag == 'VARDEF' - call add(result[2], tree) - elseif tree.tag == 'METHODDEF' - call add(result[1], tree) - elseif tree.tag == 'CLASSDEF' - call add(result[0], tree.name) - endif - endfor - - if a:first && result != [[], [], [], []] | return result | endif - - " Accessible inherited members - let type = get(s:SearchTypeAt(unit, targetPos), -1, {}) - if !empty(type) - let members = s:SearchMember(type, a:name, a:fullmatch, 2, 1, 0, 1) - let result[0] += members[0] - let result[1] += members[1] - let result[2] += members[2] -" "let ti = s:AddInheritedClassInfo({}, type) -" if !empty(ti) -" let comparator = a:fullmatch ? "=~# '^" : "==# '" -" let result[0] += s:filter(get(ti, 'classes', []), 'item ' . comparator . a:name . "'") -" let result[1] += s:filter(get(ti, 'methods', []), 'item.n ' . comparator . a:name . "'") -" let result[2] += s:filter(get(ti, 'fields', []), 'item.n ' . comparator . a:name . "'") -" if a:0 > 0 -" let result[1] += s:filter(get(ti, 'declared_methods', []), 'item.n ' . comparator . a:name . "'") -" let result[2] += s:filter(get(ti, 'declared_fields', []), 'item.n ' . comparator . a:name . "'") -" endif -" if a:first && result != [[], [], [], []] | return result | endif -" endif - endif - - " static import - let si = s:SearchStaticImports(a:name, a:fullmatch) - let result[1] += si[1] - let result[2] += si[2] - endif - return result -endfu - -" TODO: how to determine overloaded functions -fu! s:DetermineMethod(methods, parameters) - return get(a:methods, 0, {}) -endfu - -" Parser.GetType() in insenvim -function! s:GetDeclaredClassName(var) - let var = s:Trim(a:var) - call s:Trace('GetDeclaredClassName for "' . var . '"') - if var =~# '^\(this\|super\)$' - return var - endif - - - " Special handling for builtin objects in JSP - if &ft == 'jsp' - if get(s:JSP_BUILTIN_OBJECTS, a:var, '') != '' - return s:JSP_BUILTIN_OBJECTS[a:var] - endif - endif - - " use java_parser.vim - if javacomplete#GetSearchdeclMethod() == 4 - let variable = get(s:SearchForName(var, 1, 1)[2], -1, {}) - return get(variable, 'tag', '') == 'VARDEF' ? java_parser#type2Str(variable.vartype) : get(variable, 't', '') - endif - - - let ic = &ignorecase - setlocal noignorecase - - let searched = javacomplete#GetSearchdeclMethod() == 2 ? s:Searchdecl(var, 1, 0) : searchdecl(var, 1, 0) - if (searched == 0) - " code sample: - " String tmp; java. - " lang. String str, value; - " for (int i = 0, j = 0; i < 10; i++) { - " j = 0; - " } - let declaration = s:GetVariableDeclaration() - " Assume it a class member, and remove modifiers - let class = substitute(declaration, '^\(public\s\+\|protected\s\+\|private\s\+\|abstract\s\+\|static\s\+\|final\s\+\|native\s\+\)*', '', '') - let class = substitute(class, '\s*\([a-zA-Z0-9_.]\+\)\(\[\]\)\?\s\+.*', '\1\2', '') - let class = substitute(class, '\([a-zA-Z0-9_.]\)<.*', '\1', '') - call s:Info('class: "' . class . '" declaration: "' . declaration . '" for ' . a:var) - let &ignorecase = ic - if class != '' && class !=# a:var && class !=# 'import' && class !=# 'class' - return class - endif - endif - - let &ignorecase = ic - call s:Trace('GetDeclaredClassName: cannot find') - return '' -endfunction - -" using java_parser.vim {{{1 -" javacomplete#parse() {{{2 -fu! javacomplete#parse(...) - let filename = a:0 == 0 ? '%' : a:1 - - let changed = 0 - if filename == '%' - let filename = s:GetCurrentFileKey() - let props = get(s:files, filename, {}) - if get(props, 'changedtick', -1) != b:changedtick - let changed = 1 - let props.changedtick = b:changedtick - let lines = getline('^', '$') - endif - else - let props = get(s:files, filename, {}) - if get(props, 'modifiedtime', 0) != getftime(filename) - let changed = 1 - let props.modifiedtime = getftime(filename) - let lines = readfile(filename) - endif - endif - - if changed - call java_parser#InitParser(lines) - call java_parser#SetLogLevel(5) - let props.unit = java_parser#compilationUnit() - - let package = has_key(props.unit, 'package') ? props.unit.package . '.' : '' - call s:UpdateFQN(props.unit, package) - endif - let s:files[filename] = props - return props.unit -endfu - -" update fqn for toplevel types or nested types. -" not for local type or anonymous type -fu! s:UpdateFQN(tree, qn) - if a:tree.tag == 'TOPLEVEL' - for def in a:tree.types - call s:UpdateFQN(def, a:qn) - endfor - elseif a:tree.tag == 'CLASSDEF' - let a:tree.fqn = a:qn . a:tree.name - for def in a:tree.defs - if def.tag == 'CLASSDEF' - call s:UpdateFQN(def, a:tree.fqn . '.') - endif - endfor - endif -endfu - -" TreeVisitor {{{2 -fu! s:visitTree(tree, param) dict - if type(a:tree) == type({}) - exe get(self, get(a:tree, 'tag', ''), '') - elseif type(a:tree) == type([]) - for tree in a:tree - call self.visit(tree, a:param) - endfor - endif -endfu - -let s:TreeVisitor = {'visit': function('s:visitTree'), - \ 'TOPLEVEL' : 'call self.visit(a:tree.types, a:param)', - \ 'BLOCK' : 'let stats = a:tree.stats | if stats == [] | call java_parser#GotoPosition(a:tree.pos) | let stats = java_parser#block().stats | endif | call self.visit(stats, a:param)', - \ 'DOLOOP' : 'call self.visit(a:tree.body, a:param) | call self.visit(a:tree.cond, a:param)', - \ 'WHILELOOP' : 'call self.visit(a:tree.cond, a:param) | call self.visit(a:tree.body, a:param)', - \ 'FORLOOP' : 'call self.visit(a:tree.init, a:param) | call self.visit(a:tree.cond, a:param) | call self.visit(a:tree.step, a:param) | call self.visit(a:tree.body, a:param)', - \ 'FOREACHLOOP' : 'call self.visit(a:tree.var, a:param) | call self.visit(a:tree.expr, a:param) | call self.visit(a:tree.body, a:param)', - \ 'LABELLED' : 'call self.visit(a:tree.body, a:param)', - \ 'SWITCH' : 'call self.visit(a:tree.selector, a:param) | call self.visit(a:tree.cases, a:param)', - \ 'CASE' : 'call self.visit(a:tree.pat, a:param) | call self.visit(a:tree.stats, a:param)', - \ 'SYNCHRONIZED': 'call self.visit(a:tree.lock, a:param) | call self.visit(a:tree.body, a:param)', - \ 'TRY' : 'call self.visit(a:tree.body, a:param) | call self.visit(a:tree.catchers, a:param) | call self.visit(a:tree.finalizer, a:param) ', - \ 'CATCH' : 'call self.visit(a:tree.param,a:param) | call self.visit(a:tree.body, a:param)', - \ 'CONDEXPR' : 'call self.visit(a:tree.cond, a:param) | call self.visit(a:tree.truepart, a:param) | call self.visit(a:tree.falsepart, a:param)', - \ 'IF' : 'call self.visit(a:tree.cond, a:param) | call self.visit(a:tree.thenpart, a:param) | if has_key(a:tree, "elsepart") | call self.visit(a:tree.elsepart, a:param) | endif', - \ 'EXEC' : 'call self.visit(a:tree.expr, a:param)', - \ 'APPLY' : 'call self.visit(a:tree.meth, a:param) | call self.visit(a:tree.args, a:param)', - \ 'NEWCLASS' : 'call self.visit(a:tree.def, a:param)' - \} - -let s:TV_CMP_POS = 'a:tree.pos <= a:param.pos && a:param.pos <= get(a:tree, "endpos", -1)' -let s:TV_CMP_POS_BODY = 'has_key(a:tree, "body") && a:tree.body.pos <= a:param.pos && a:param.pos <= get(a:tree.body, "endpos", -1)' - -" Return a stack of enclosing types (including local or anonymous classes). -" Given the optional argument, return all (toplevel or static member) types besides enclosing types. -fu! s:SearchTypeAt(tree, targetPos, ...) - let s:TreeVisitor.CLASSDEF = 'if a:param.allNonLocal || ' . s:TV_CMP_POS . ' | call add(a:param.result, a:tree) | call self.visit(a:tree.defs, a:param) | endif' - let s:TreeVisitor.METHODDEF = 'if ' . s:TV_CMP_POS_BODY . ' | call self.visit(a:tree.body, a:param) | endif' - let s:TreeVisitor.VARDEF = 'if has_key(a:tree, "init") && !a:param.allNonLocal && ' . s:TV_CMP_POS . ' | call self.visit(a:tree.init, a:param) | endif' - - let result = [] - call s:TreeVisitor.visit(a:tree, {'result': result, 'pos': a:targetPos, 'allNonLocal': a:0 == 0 ? 0 : 1}) - return result -endfu - -" a:1 match beginning -" return a stack of matching name -fu! s:SearchNameInAST(tree, name, targetPos, fullmatch) - let comparator = a:fullmatch ? '==#' : '=~# "^" .' - let cmd = 'if a:tree.name ' .comparator. ' a:param.name | call add(a:param.result, a:tree) | endif' - let s:TreeVisitor.CLASSDEF = 'if ' . s:TV_CMP_POS . ' | ' . cmd . ' | call self.visit(a:tree.defs, a:param) | endif' - let s:TreeVisitor.METHODDEF = cmd . ' | if ' . s:TV_CMP_POS_BODY . ' | call self.visit(a:tree.params, a:param) | call self.visit(a:tree.body, a:param) | endif' - let s:TreeVisitor.VARDEF = cmd . ' | if has_key(a:tree, "init") && ' . s:TV_CMP_POS . ' | call self.visit(a:tree.init, a:param) | endif' - - let result = [] - call s:TreeVisitor.visit(a:tree, {'result': result, 'pos': a:targetPos, 'name': a:name}) - "call s:Info(a:name . ' ' . string(result) . ' line: ' . line('.') . ' col: ' . col('.')) . ' ' . a:targetPos - return result -endfu - - -" javacomplete#Searchdecl {{{2 -" TODO: -fu! javacomplete#Searchdecl() - let var = expand('') - - let line = line('.')-1 - let col = col('.')-1 - - - if var =~# '^\(this\|super\)$' - if &ft == 'jsp' - return '' - endif - - let matchs = s:SearchTypeAt(javacomplete#parse(), java_parser#MakePos(line, col)) - - let stat = s:GetStatement() - for t in matchs - if stat =~ t.name - let coor = java_parser#DecodePos(t.pos) - return var . '(' . (coor.line+1) . ',' . (coor.col) . ') ' . getline(coor.line+1) - endif - endfor - if len(matchs) > 0 - let coor = java_parser#DecodePos(matchs[len(matchs)-1].pos) - return var . '(' . (coor.line+1) . ',' . (coor.col) . ') ' . getline(coor.line+1) - endif - return '' - endif - - " Type.this. - " new Type() - " new Type(param1, param2) - " this.field - " super.field - - let s:log = [] - - - " It may be an imported class. - let imports = [] - for fqn in s:GetImports('imports_fqn') - if fqn =~# '\<' . var . '\>$' - call add(imports, fqn) - endif - endfor - if len(imports) > 1 - echoerr 'Imports conflicts between ' . join(imports, ' and ') - endif - - - " Search in this buffer - let matchs = s:SearchNameInAST(javacomplete#parse(), var, java_parser#MakePos(line, col), 1) - - - let hint = var . ' ' - if !empty(matchs) - let tree = matchs[len(matchs)-1] - let coor = java_parser#DecodePos(tree.pos) - let hint .= '(' . (coor.line+1) . ',' . (coor.col) . ') ' - let hint .= getline(coor.line+1) "string(tree) - else - for fqn in imports - let ci = s:DoGetClassInfo(fqn) - if !empty(ci) - let hint .= ' ' . fqn - endif - " TODO: get javadoc - endfor - - endif - return hint -endfu - - -" java {{{1 - -fu! s:IsBuiltinType(name) - return index(s:PRIMITIVE_TYPES, a:name) >= 0 -endfu - -fu! s:IsKeyword(name) - return index(s:KEYWORDS, a:name) >= 0 -endfu - -fu! s:HasKeyword(name) - return a:name =~# s:RE_KEYWORDS -endfu - -fu! s:TailOfQN(qn) - return a:qn[strridx(a:qn, '.')+1:] -endfu - -" options {{{1 -" Methods to search declaration {{{2 -" 1 - by builtin searchdecl() -" 2 - by special Searchdecl() -" 4 - by java_parser -fu! javacomplete#GetSearchdeclMethod() - if &ft == 'jsp' - return 1 - endif - return exists('s:searchdecl') ? s:searchdecl : 4 -endfu - -fu! javacomplete#SetSearchdeclMethod(method) - let s:searchdecl = a:method -endfu - -" JDK1.1 {{{2 -fu! javacomplete#UseJDK11() - let s:isjdk11 = 1 -endfu - -" java compiler {{{2 -fu! javacomplete#GetCompiler() - return exists('s:compiler') && s:compiler !~ '^\s*$' ? s:compiler : 'javac' -endfu - -fu! javacomplete#SetCompiler(compiler) - let s:compiler = a:compiler -endfu - -" jvm launcher {{{2 -fu! javacomplete#GetJVMLauncher() - return exists('s:interpreter') && s:interpreter !~ '^\s*$' ? s:interpreter : 'java' -endfu - -fu! javacomplete#SetJVMLauncher(interpreter) - if javacomplete#GetJVMLauncher() != a:interpreter - let s:cache = {} - endif - let s:interpreter = a:interpreter -endfu - -" sourcepath {{{2 -fu! javacomplete#AddSourcePath(s) - if !isdirectory(a:s) - echoerr 'invalid source path: ' . a:s - return - endif - let path = fnamemodify(a:s, ':p:h') - if !exists('s:sourcepath') - let s:sourcepath = [path] - elseif index(s:sourcepath, path) == -1 - call add(s:sourcepath, path) - endif -endfu - -fu! javacomplete#DelSourcePath(s) - if !exists('s:sourcepath') || !isdirectory(a:s)| return | endif - let idx = index(s:sourcepath, a:s) - if idx != -1 - call remove(s:sourcepath, idx) - endif -endfu - -fu! javacomplete#SetSourcePath(s) - let paths = type(a:s) == type([]) ? a:s : split(a:s, javacomplete#GetClassPathSep()) - let s:sourcepath = [] - for path in paths - if isdirectory(path) - call add(s:sourcepath, fnamemodify(path, ':p:h')) - endif - endfor -endfu - -" return the sourcepath. Given argument, add current path or default package root path -" NOTE: Avoid path duplicate, otherwise globpath() will return duplicate result. -fu! javacomplete#GetSourcePath(...) - return join(s:GetSourceDirs(a:0 > 0 && a:1 ? expand('%:p') : ''), s:PATH_SEP) -endfu - -fu! s:GetSourceDirs(filepath, ...) - let dirs = exists('s:sourcepath') ? s:sourcepath : [] - - if !empty(a:filepath) - let filepath = fnamemodify(a:filepath, ':p:h') - - " get source path according to file path and package name - let packageName = a:0 > 0 ? a:1 : s:GetPackageName() - if packageName != '' - let path = fnamemodify(substitute(filepath, packageName, '', 'g'), ':p:h') - if index(dirs, path) < 0 - call add(dirs, path) - endif - endif - - " Consider current path as a sourcepath - if index(dirs, filepath) < 0 - call add(dirs, filepath) - endif - endif - return dirs -endfu - -" classpath {{{2 -fu! javacomplete#AddClassPath(s) - if !isdirectory(a:s) - echoerr 'invalid classpath: ' . a:s - return - endif - - if !exists('s:classpath') - let s:classpath = [a:s] - elseif index(s:classpath, a:s) == -1 - call add(s:classpath, a:s) - endif - let s:cache = {} -endfu - -fu! javacomplete#DelClassPath(s) - if !exists('s:classpath') | return | endif - let idx = index(s:classpath, a:s) - if idx != -1 - call remove(s:classpath, idx) - endif -endfu - -fu! javacomplete#SetClassPath(s) - if type(a:s) == type("") - let s:classpath = split(a:s, javacomplete#GetClassPathSep()) - elseif type(a:s) == type([]) - let s:classpath = a:s - endif - let s:cache = {} -endfu - -fu! javacomplete#GetClassPathSep() - return s:PATH_SEP -endfu - -fu! javacomplete#GetClassPath() - return exists('s:classpath') ? join(s:classpath, javacomplete#GetClassPathSep()) : '' -endfu - -" s:GetClassPath() {{{2 -fu! s:GetClassPath() - let path = s:GetJavaCompleteClassPath() . javacomplete#GetClassPathSep() - - if &ft == 'jsp' - let path .= s:GetClassPathOfJsp() - endif - - if exists('b:classpath') && b:classpath !~ '^\s*$' - return path . b:classpath - endif - - if exists('s:classpath') - return path . javacomplete#GetClassPath() - endif - - if exists('g:java_classpath') && g:java_classpath !~ '^\s*$' - return path . g:java_classpath - endif - - return path . $CLASSPATH -endfu - -fu! s:GetJavaCompleteClassPath() - " remove *.class from wildignore if it exists, so that globpath doesn't ignore Reflection.class - " vim versions >= 702 can add the 1 flag to globpath which ignores '*.class" in wildingore - let has_class = 0 - if &wildignore =~# "*.class" - set wildignore-=*.class - let has_class = 1 - endif - - let classfile = globpath(&rtp, 'autoload/Reflection.class') - if classfile == '' - let classfile = globpath($HOME, 'Reflection.class') - endif - if classfile == '' - " try to find source file and compile to $HOME - let srcfile = globpath(&rtp, 'autoload/Reflection.java') - if srcfile != '' - exe '!' . javacomplete#GetCompiler() . ' -d "' . $HOME . '" "' . srcfile . '"' - let classfile = globpath($HOME, 'Reflection.class') - if classfile == '' - echo srcfile . ' can not be compiled. Please check it' - endif - else - echo 'No Reflection.class found in $HOME or any autoload directory of the &rtp. And no Reflection.java found in any autoload directory of the &rtp to compile.' - endif - endif - - " add *.class to wildignore if it existed before - if has_class == 1 - set wildignore+=*.class - endif - - return fnamemodify(classfile, ':p:h') -endfu - -fu! s:GetClassPathOfJsp() - if exists('b:classpath_jsp') - return b:classpath_jsp - endif - - let b:classpath_jsp = '' - let path = expand('%:p:h') - while 1 - if isdirectory(path . '/WEB-INF' ) - if isdirectory(path . '/WEB-INF/classes') - let b:classpath_jsp .= s:PATH_SEP . path . '/WEB-INF/classes' - endif - if isdirectory(path . '/WEB-INF/lib') - let libs = globpath(path . '/WEB-INF/lib', '*.jar') - if libs != '' - let b:classpath_jsp .= s:PATH_SEP . substitute(libs, "\n", s:PATH_SEP, 'g') - endif - endif - return b:classpath_jsp - endif - - let prev = path - let path = fnamemodify(path, ":p:h:h") - if path == prev - break - endif - endwhile - return '' -endfu - -" return only classpath which are directories -fu! s:GetClassDirs() - let dirs = [] - for path in split(s:GetClassPath(), s:PATH_SEP) - if isdirectory(path) - call add(dirs, fnamemodify(path, ':p:h')) - endif - endfor - return dirs -endfu - -" s:GetPackageName() {{{2 -fu! s:GetPackageName() - let lnum_old = line('.') - let col_old = col('.') - - call cursor(1, 1) - let lnum = search('^\s*package[ \t\r\n]\+\([a-zA-Z][a-zA-Z0-9.]*\);', 'w') - let packageName = substitute(getline(lnum), '^\s*package\s\+\([a-zA-Z][a-zA-Z0-9.]*\);', '\1', '') - - call cursor(lnum_old, col_old) - return packageName -endfu - -fu! s:IsStatic(modifier) - return a:modifier[strlen(a:modifier)-4] -endfu - -" utilities {{{1 -" Convert a file name into the unique form. -" Similar with fnamemodify(). NOTE that ':gs' should not be used. -fu! s:fnamecanonize(fname, mods) - return fnamemodify(a:fname, a:mods . ':gs?[\\/]\+?/?') -endfu - -" Similar with filter(), but returns a new list instead of operating in-place. -" `item` has the value of the current item. -fu! s:filter(expr, string) - if type(a:expr) == type([]) - let result = [] - for item in a:expr - if eval(a:string) - call add(result, item) - endif - endfor - return result - else - let result = {} - for item in items(a:expr) - if eval(a:string) - let result[item[0]] = item[1] - endif - endfor - return result - endif -endfu - -fu! s:Index(list, expr, key) - let i = 0 - while i < len(a:list) - if get(a:list[i], a:key, '') == a:expr - return i - endif - let i += 1 - endwhile - return -1 -endfu - -fu! s:Match(list, expr, key) - let i = 0 - while i < len(a:list) - if get(a:list[i], a:key, '') =~ a:expr - return i - endif - let i += 1 - endwhile - return -1 -endfu - -fu! s:KeepCursor(cmd) - let lnum_old = line('.') - let col_old = col('.') - exe a:cmd - call cursor(lnum_old, col_old) -endfu - -fu! s:InCommentOrLiteral(line, col) - if has("syntax") && &ft != 'jsp' - return synIDattr(synID(a:line, a:col, 1), "name") =~? '\(Comment\|String\|Character\)' - endif -endfu - -function! s:InComment(line, col) - if has("syntax") && &ft != 'jsp' - return synIDattr(synID(a:line, a:col, 1), "name") =~? 'comment' - endif -" if getline(a:line) =~ '\s*\*' -" return 1 -" endif -" let idx = strridx(getline(a:line), '//') -" if idx >= 0 && idx < a:col -" return 1 -" endif -" return 0 -endfunction - -" set string literal empty, remove comments, trim begining or ending spaces -" test case: ' sb. /* block comment*/ append( "stringliteral" ) // comment ' -function! s:Prune(str, ...) - if a:str =~ '^\s*$' | return '' | endif - - let str = substitute(a:str, '"\(\\\(["\\''ntbrf]\)\|[^"]\)*"', '""', 'g') - let str = substitute(str, '\/\/.*', '', 'g') - let str = s:RemoveBlockComments(str) - return a:0 > 0 ? str : str . ' ' -endfunction - -" Given argument, replace block comments with spaces of same number -fu! s:RemoveBlockComments(str, ...) - let result = a:str - let ib = match(result, '\/\*') - let ie = match(result, '\*\/') - while ib != -1 && ie != -1 && ib < ie - let result = strpart(result, 0, ib) . (a:0 == 0 ? ' ' : repeat(' ', ie-ib+2)) . result[ie+2: ] - let ib = match(result, '\/\*') - let ie = match(result, '\*\/') - endwhile - return result -endfu - -fu! s:Trim(str) - let str = substitute(a:str, '^\s*', '', '') - return substitute(str, '\s*$', '', '') -endfu - -fu! s:SplitAt(str, index) - return [strpart(a:str, 0, a:index+1), strpart(a:str, a:index+1)] -endfu - -" TODO: search pair used in string, like -" 'create(ao.fox("("), new String).foo().' -function! s:GetMatchedIndexEx(str, idx, one, another) - let pos = a:idx - while 0 <= pos && pos < len(a:str) - let pos = match(a:str, '['. a:one . escape(a:another, ']') .']', pos+1) - if pos != -1 - if a:str[pos] == a:one - let pos = s:GetMatchedIndexEx(a:str, pos, a:one, a:another) - elseif a:str[pos] == a:another - break - endif - endif - endwhile - return 0 <= pos && pos < len(a:str) ? pos : -3 -endfunction - -function! s:SearchPairBackward(str, idx, one, another) - let idx = a:idx - let n = 0 - while idx >= 0 - let idx -= 1 - if a:str[idx] == a:one - if n == 0 - break - endif - let n -= 1 - elseif a:str[idx] == a:another " nested - let n += 1 - endif - endwhile - return idx -endfunction - -fu! s:CountDims(str) - if match(a:str, '[[\]]') == -1 - return 0 - endif - - " int[] -> [I, String[] -> - let dims = len(matchstr(a:str, '^[\+')) - if dims == 0 - let idx = len(a:str)-1 - while idx >= 0 && a:str[idx] == ']' - let dims += 1 - let idx = s:SearchPairBackward(a:str, idx, '[', ']')-1 - endwhile - endif - return dims -endfu - -fu! s:GotoUpperBracket() - let searched = 0 - while (!searched) - call search('[{}]', 'bW') - if getline('.')[col('.')-1] == '}' - normal % - else - let searched = 1 - endif - endwhile -endfu - -" Improve recognition of variable declaration using my version of searchdecl() for accuracy reason. -" TODO: -fu! s:Searchdecl(name, ...) - let global = a:0 > 0 ? a:1 : 0 - let thisblock = a:0 > 1 ? a:2 : 1 - - call search('\<' . a:name . '\>', 'bW') - let lnum_old = line('.') - let col_old = col('.') - - call s:GotoUpperBracket() - let lnum_bracket = line('.') - let col_bracket = col('.') - call search('\<' . a:name . '\>', 'W', lnum_old) - if line('.') != lnum_old || col('.') != col_old - return 0 - endif - - " search globally - if global - call cursor(lnum_bracket, col_bracket) - " search backward - while (1) - if search('\([{}]\|\<' . a:name . '\>\)', 'bW') == 0 - break - endif - if s:InComment(line('.'), col('.')) "|| s:InStringLiteral() - continue - endif - let cword = expand('') - if cword == a:name - return 0 - endif - if getline('.')[col('.')-1] == '}' - normal % - endif - endwhile - - call cursor(lnum_old, col_old) - " search forward - call search('[{};]', 'W') - while (1) - if search('\([{}]\|\<' . a:name . '\>\)', 'W') == 0 - break - endif - if s:InComment(line('.'), col('.')) "|| s:InStringLiteral() - continue - endif - let cword = expand('') - if cword == a:name - return 0 - endif - if getline('.')[col('.')-1] == '{' - normal % - endif - endwhile - endif - return 1 -endfu -"nmap :call Searchdecl(expand('')) - -fu! javacomplete#Exe(cmd) - exe a:cmd -endfu - -" cache utilities {{{1 - -" key of s:files for current buffer. It may be the full path of current file or the bufnr of unnamed buffer, and is updated when BufEnter, BufLeave. -fu! s:GetCurrentFileKey() - return has("autocmd") ? s:curfilekey : empty(expand('%')) ? bufnr('%') : expand('%:p') -endfu - -fu! s:SetCurrentFileKey() - let s:curfilekey = empty(expand('%')) ? bufnr('%') : expand('%:p') -endfu - -call s:SetCurrentFileKey() -if has("autocmd") - autocmd BufEnter *.java call s:SetCurrentFileKey() - autocmd FileType java call s:SetCurrentFileKey() -endif - - -" Log utilities {{{1 -fu! s:WatchVariant(variant) - "echoerr a:variant -endfu - -" level -" 5 off/fatal -" 4 error -" 3 warn -" 2 info -" 1 debug -" 0 trace -fu! javacomplete#SetLogLevel(level) - let s:loglevel = a:level -endfu - -fu! javacomplete#GetLogLevel() - return exists('s:loglevel') ? s:loglevel : 3 -endfu - -fu! javacomplete#GetLogContent() - return s:log -endfu - -fu! s:Trace(msg) - call s:Log(0, a:msg) -endfu - -fu! s:Debug(msg) - call s:Log(1, a:msg) -endfu - -fu! s:Info(msg) - call s:Log(2, a:msg) -endfu - -fu! s:Log(level, key, ...) - if a:level >= javacomplete#GetLogLevel() - echo a:key - call add(s:log, a:key) - endif -endfu - -fu! s:System(cmd, caller) - call s:WatchVariant(a:cmd) - let t = reltime() - let res = system(a:cmd) - call s:Debug(reltimestr(reltime(t)) . 's to exec "' . a:cmd . '" by ' . a:caller) - return res -endfu - -" functions to get information {{{1 -" utilities {{{2 -fu! s:MemberCompare(m1, m2) - return a:m1['n'] == a:m2['n'] ? 0 : a:m1['n'] > a:m2['n'] ? 1 : -1 -endfu - -fu! s:Sort(ci) - let ci = a:ci - if has_key(ci, 'fields') - call sort(ci['fields'], 's:MemberCompare') - endif - if has_key(ci, 'methods') - call sort(ci['methods'], 's:MemberCompare') - endif - return ci -endfu - -" Function to run Reflection {{{2 -fu! s:RunReflection(option, args, log) - let classpath = '' - if !exists('s:isjdk11') - let classpath = ' -classpath "' . s:GetClassPath() . '" ' - endif - - let cmd = javacomplete#GetJVMLauncher() . classpath . ' Reflection ' . a:option . ' "' . a:args . '"' - return s:System(cmd, a:log) -endfu -" class information {{{2 - - -" The standard search order of a FQN is as follows: -" 1. a file-name toplevel type or static member type accessed by the file-name type declared in source files -" 2. other types declared in source files -" 3. an accessible loadable type. -" parameters: -" fqns - list of fqn -" srcpaths - a comma-separated list of directory names. -" a:1 - search all. -" return a dict of fqn -> type info -" precondition: -" NOTE: call expand() to convert path to standard form -fu! s:DoGetTypeInfoForFQN(fqns, srcpath, ...) - if empty(a:fqns) || empty(a:srcpath) - return - endif - - " 1 - let files = {} " fqn -> java file path - for fqn in a:fqns - " toplevel type - let filepath = globpath(a:srcpath, substitute(fqn, '\.', '/', 'g') . '.java') - if filepath != '' - let files[fqn] = expand(filepath) - - " nested type - elseif stridx(fqn, '.') >= 0 - let idents = split(fqn, '\.') - let i = len(idents)-2 - while i >= 0 - let filepath = globpath(a:srcpath, join(idents[:i], '/') . '.java') - if filepath != '' - let files[fqn] = expand(filepath) - break - endif - let i -= 1 - endwhile - endif - endfor - - - " 2 - let dirs = {} " dir.idents -> names of nested type - " dir.qfitems -> items of quick fix - " dir.fqn -> fqn - for fqn in a:fqns - if !has_key(files, fqn) - for path in split(a:srcpath, ',') - let idents = split(fqn, '\.') - let i = len(idents)-2 - while i >= 0 - let dirpath = path . '/' . join(idents[:i], '/') - " it is a package - if isdirectory(dirpath) - let dirs[fnamemodify(dirpath, ':p:h:gs?[\\/]\+?/?')] = {'fqn': fqn, 'idents': idents[i+1:]} - break - endif - let i -= 1 - endwhile - endfor - endif - endfor - - if !empty(dirs) - let items = {} " dir -> items of quick fix - - let filepatterns = '' - for dirpath in keys(dirs) - let filepatterns .= escape(dirpath, ' \') . '/*.java ' - endfor - - let cwd = fnamemodify(expand('%:p:h'), ':p:h:gs?[\\/]\+?/?') - exe 'vimgrep /\s*' . s:RE_TYPE_DECL . '/jg ' . filepatterns - for item in getqflist() - if item.text !~ '^\s*\*\s\+' - let text = matchstr(s:Prune(item.text, -1), '\s*' . s:RE_TYPE_DECL) - if text != '' - let subs = split(substitute(text, '\s*' . s:RE_TYPE_DECL, '\1;\2;\3', ''), ';', 1) - let dirpath = fnamemodify(bufname(item.bufnr), ':p:h:gs?[\\/]\+?/?') - let idents = dirs[dirpath].idents - if index(idents, subs[2]) >= 0 && (subs[0] =~ '\C\' || dirpath == cwd) " FIXME? - let item.subs = subs - let dirs[dirpath].qfitems = get(dirs[dirpath], 'qfitems', []) + [item] - endif - endif - endif - endfor - - for dirpath in keys(dirs) - " a. names of nested type must be existed in the same file - " PackageName.NonFileNameTypeName.NestedType.NestedNestedType - let qfitems = get(dirs[dirpath], 'qfitems', []) - let nr = 0 - for ident in dirs[dirpath].idents - for item in qfitems - if item.subs[2] == ident - let nr += 1 - endif - endfor - endfor - if nr == len(dirs[dirpath].idents) - " b. TODO: Check whether one enclosed another is correct - let files[fqn] = expand(bufname(qfitems[0].bufnr)) - endif - endfor - endif - - - call s:Info('FQN1&2: ' . string(keys(files))) - for fqn in keys(files) - if !has_key(s:cache, fqn) || get(get(s:files, files[fqn], {}), 'modifiedtime', 0) != getftime(files[fqn]) - let ti = s:GetClassInfoFromSource(fqn[strridx(fqn, '.')+1:], files[fqn]) - if !empty(ti) - let s:cache[fqn] = s:Sort(ti) - endif - endif - if (a:0 == 0 || !a:1) - return - endif - endfor - - - " 3 - let commalist = '' - for fqn in a:fqns - if has_key(s:cache, fqn) && (a:0 == 0 || !a:1) - return - else "if stridx(fqn, '.') >= 0 - let commalist .= fqn . ',' - endif - endfor - if !empty(commalist) - let res = s:RunReflection('-E', commalist, 'DoGetTypeInfoForFQN in Batch') - if res =~ "^{'" - let dict = eval(res) - for key in keys(dict) - if !has_key(s:cache, key) - if type(dict[key]) == type({}) - let s:cache[key] = s:Sort(dict[key]) - elseif type(dict[key]) == type([]) - let s:cache[key] = sort(dict[key]) - endif - endif - endfor - endif - endif -endfu - -" a:1 filepath -" a:2 package name -fu! s:DoGetClassInfo(class, ...) - if has_key(s:cache, a:class) - return s:cache[a:class] - endif - - " array type: TypeName[] or '[I' or '[[Ljava.lang.String;' - if a:class[-1:] == ']' || a:class[0] == '[' - return s:ARRAY_TYPE_INFO - endif - - " either this or super is not qualified - if a:class == 'this' || a:class == 'super' - if &ft == 'jsp' - let ci = s:DoGetReflectionClassInfo('javax.servlet.jsp.HttpJspPage') - if a:class == 'this' - " TODO: search methods defined in <%! [declarations] %> - " search methods defined in other jsp files included - " avoid including self directly or indirectly - endif - return ci - endif - - call s:Info('A0. ' . a:class) - " this can be a local class or anonymous class as well as static type - let t = get(s:SearchTypeAt(javacomplete#parse(), java_parser#MakePos(line('.')-1, col('.')-1)), -1, {}) - if !empty(t) - " What will be returned for super? - " - the protected or public inherited fields and methods. No ctors. - " - the (public static) fields of interfaces. - " - the methods of the Object class. - " What will be returned for this? - " - besides the above, all fields and methods of current class. No ctors. - return s:Sort(s:Tree2ClassInfo(t)) - "return s:Sort(s:AddInheritedClassInfo(a:class == 'this' ? s:Tree2ClassInfo(t) : {}, t, 1)) - endif - - return {} - endif - - - if a:class !~ '^\s*' . s:RE_QUALID . '\s*$' || s:HasKeyword(a:class) - return {} - endif - - - let typename = substitute(a:class, '\s', '', 'g') - let filekey = a:0 > 0 ? a:1 : s:GetCurrentFileKey() - let packagename = a:0 > 1 ? a:2 : s:GetPackageName() - let srcpath = join(s:GetSourceDirs(a:0 > 0 && a:1 != bufnr('%') ? a:1 : expand('%:p'), packagename), ',') - - let names = split(typename, '\.') - " remove the package name if in the same packge - if len(names) > 1 - if packagename == join(names[:-2], '.') - let names = names[-1:] - endif - endif - - " a FQN - if len(names) > 1 - call s:DoGetTypeInfoForFQN([typename], srcpath) - let ci = get(s:cache, typename, {}) - if get(ci, 'tag', '') == 'CLASSDEF' - return s:cache[typename] - elseif get(ci, 'tag', '') == 'PACKAGE' - return {} - endif - endif - - - " The standard search order of a simple type name is as follows: - " 1. The current type including inherited types. - " 2. A nested type of the current type. - " 3. Explicitly named imported types (single type import). - " 4. Other types declared in the same package. Not only current directory. - " 5. Implicitly named imported types (import on demand). - - " 1 & 2. - " NOTE: inherited types are treated as normal - if filekey == s:GetCurrentFileKey() - let simplename = typename[strridx(typename, '.')+1:] - if s:FoundClassDeclaration(simplename) != 0 - call s:Info('A1&2') - let ci = s:GetClassInfoFromSource(simplename, '%') - " do not cache it - if !empty(ci) - return ci - endif - endif - else - let ci = s:GetClassInfoFromSource(typename, filekey) - if !empty(ci) - return ci - endif - endif - - " 3. - " NOTE: PackageName.Ident, TypeName.Ident - let fqn = s:SearchSingleTypeImport(typename, s:GetImports('imports_fqn', filekey)) - if !empty(fqn) - call s:Info('A3') - call s:DoGetTypeInfoForFQN([fqn], srcpath) - let ti = get(s:cache, fqn, {}) - if get(ti, 'tag', '') != 'CLASSDEF' - " TODO: mark the wrong import declaration. - endif - return ti - endif - - " 4 & 5 - " NOTE: Keeps the fqn of the same package first!! - call s:Info('A4&5') - let fqns = [empty(packagename) ? typename : packagename . '.' . typename] - for p in s:GetImports('imports_star', filekey) - call add(fqns, p . typename) - endfor - call s:DoGetTypeInfoForFQN(fqns, srcpath) - for fqn in fqns - if has_key(s:cache, fqn) - return get(s:cache[fqn], 'tag', '') == 'CLASSDEF' ? s:cache[fqn] : {} - endif - endfor - - return {} -endfu - -" Rules of overriding and hiding: -" 1. Fields cannot be overridden; they can only be hidden. -" In the subclass, the hidden field of superclass can no longer be accessed -" directly by its simple name. `super` or another reference must be used. -" 2. A method can be overriden only if it is accessible. -" When overriding methods, both the signature and return type must be the -" same as in the superclass. -" 3. Static members cannot be overridden; they can only be hidden -" -- whether a field or a method. But hiding static members has little effect, -" because static should be accessed via the name of its declaring class. -" Given optional argument, add protected, default (package) access, private members. -"fu! s:MergeClassInfo(ci, another, ...) -" if empty(a:another) | return a:ci | endif -" -" if empty(a:ci) -" let ci = copy(a:another) -"" if a:0 > 0 && a:1 -"" call extend(ci.fields, get(a:another, 'declared_fields', [])) -"" call extend(ci.methods, get(a:another, 'declared_methods', [])) -"" endif -" return ci -" endif -" -" call extend(a:ci.methods, a:another.methods) -" -" for f in a:another.fields -" if s:Index(a:ci.fields, f.n, 'n') < 0 -" call add(a:ci.fields, f) -" endif -" endfor -" return a:ci -"endfu - - -" Parameters: -" class the qualified class name -" Return: TClassInfo or {} when not found -" See ClassInfoFactory.getClassInfo() in insenvim. -function! s:DoGetReflectionClassInfo(fqn) - if !has_key(s:cache, a:fqn) - let res = s:RunReflection('-C', a:fqn, 's:DoGetReflectionClassInfo') - if res =~ '^{' - let s:cache[a:fqn] = s:Sort(eval(res)) - elseif res =~ '^[' - for type in eval(res) - if get(type, 'name', '') != '' - let s:cache[type.name] = s:Sort(type) - endif - endfor - else - let b:errormsg = res - endif - endif - return get(s:cache, a:fqn, {}) -endfunction - -fu! s:GetClassInfoFromSource(class, filename) - let ci = {} - if len(tagfiles()) > 0 - let ci = s:DoGetClassInfoFromTags(a:class) - endif - - if empty(ci) - call s:Info('Use java_parser.vim to generate class information') - let unit = javacomplete#parse(a:filename) - let targetPos = a:filename == '%' ? java_parser#MakePos(line('.')-1, col('.')-1) : -1 - for t in s:SearchTypeAt(unit, targetPos, 1) - if t.name == a:class - let t.filepath = a:filename == '%' ? s:GetCurrentFileKey() : expand(a:filename) - return s:Tree2ClassInfo(t) - "return s:AddInheritedClassInfo(s:Tree2ClassInfo(t), t) - endif - endfor - endif - return ci -endfu - -fu! s:Tree2ClassInfo(t) - let t = a:t - - " fill fields and methods - let t.fields = [] - let t.methods = [] - let t.ctors = [] - let t.classes = [] - for def in t.defs - if def.tag == 'METHODDEF' - call add(def.n == t.name ? t.ctors : t.methods, def) - elseif def.tag == 'VARDEF' - call add(t.fields, def) - elseif def.tag == 'CLASSDEF' - call add(t.classes, t.fqn . '.' . def.name) - endif - endfor - - " convert type name in extends to fqn for class defined in source files - if !has_key(a:t, 'classpath') && has_key(a:t, 'extends') - if has_key(a:t, 'filepath') && a:t.filepath != s:GetCurrentFileKey() - let filepath = a:t.filepath - let packagename = get(s:files[filepath].unit, 'package', '') - else - let filepath = expand('%:p') - let packagename = s:GetPackageName() - endif - - let extends = a:t.extends - let i = 0 - while i < len(extends) - let ci = s:DoGetClassInfo(java_parser#type2Str(extends[i]), filepath, packagename) - if has_key(ci, 'fqn') - let extends[i] = ci.fqn - endif - let i += 1 - endwhile - endif - - return t -endfu - -"fu! s:AddInheritedClassInfo(ci, t, ...) -" let ci = a:ci -" " add inherited fields and methods -" let list = [] -" for i in get(a:t, 'extends', []) -" call add(list, java_parser#type2Str(i)) -" endfor -" -" if has_key(a:t, 'filepath') && a:t.filepath != expand('%:p') -" let filepath = a:t.filepath -" let props = get(s:files, a:t.filepath, {}) -" let packagename = get(props.unit, 'package', '') -" else -" let filepath = expand('%:p') -" let packagename = s:GetPackageName() -" endif -" -" for id in list -" let ci = s:MergeClassInfo(ci, s:DoGetClassInfo(id, filepath, packagename), a:0 > 0 && a:1) -" endfor -" return ci -"endfu - -" To obtain information of the class in current file or current folder, or -" even in current project. -function! s:DoGetClassInfoFromTags(class) - " find tag of a:class declaration - let tags = taglist('^' . a:class) - let filename = '' - let cmd = '' - for tag in tags - if has_key(tag, 'kind') - if tag['kind'] == 'c' - let filename = tag['filename'] - let cmd = tag['cmd'] - break - endif - endif - endfor - - let tags = taglist('^' . (empty(b:incomplete) ? '.*' : b:incomplete) ) - if filename != '' - call filter(tags, "v:val['filename'] == '" . filename . "' && has_key(v:val, 'class') ? v:val['class'] == '" . a:class . "' : 1") - endif - - let ci = {'name': a:class} - " extends and implements - let ci['ctors'] = [] - let ci['fields'] = [] - let ci['methods'] = [] - - " members - for tag in tags - let member = {'n': tag['name']} - - " determine kind - let kind = 'm' - if has_key(tag, 'kind') - let kind = tag['kind'] - endif - - let cmd = tag['cmd'] - if cmd =~ '\' - let member['m'] = '1000' - else - let member['m'] = '' - endif - - let desc = substitute(cmd, '/^\s*', '', '') - let desc = substitute(desc, '\s*{\?\s*$/$', '', '') - - if kind == 'm' - " description - if cmd =~ '\' - let desc = substitute(desc, '\s\+static\s\+', ' ', '') - endif - let member['d'] = desc - - let member['p'] = '' - let member['r'] = '' - if tag['name'] == a:class - call add(ci['ctors'], member) - else - call add(ci['methods'], member) - endif - elseif kind == 'f' - let member['t'] = substitute(desc, '\([a-zA-Z0-9_[\]]\)\s\+\<' . tag['name'] . '\>.*$', '\1', '') - call add(ci['fields'], member) - endif - endfor - return ci -endfu - -" package information {{{2 - -fu! s:DoGetInfoByReflection(class, option) - if has_key(s:cache, a:class) - return s:cache[a:class] - endif - - let res = s:RunReflection(a:option, a:class, 's:DoGetInfoByReflection') - if res =~ '^[{\[]' - let v = eval(res) - if type(v) == type([]) - let s:cache[a:class] = sort(v) - elseif type(v) == type({}) - if get(v, 'tag', '') =~# '^\(PACKAGE\|CLASSDEF\)$' - let s:cache[a:class] = v - else - call extend(s:cache, v, 'force') - endif - endif - unlet v - else - let b:errormsg = res - endif - - return get(s:cache, a:class, {}) -endfu - -" search in members {{{2 -" TODO: what about default access? -" public for all -" protected for this or super -" private for this -fu! s:CanAccess(mods, kind) - return (a:mods[-4:-4] || a:kind/10 == 0) - \ && (a:kind == 1 || a:mods[-1:] - \ || (a:mods[-3:-3] && (a:kind == 1 || a:kind == 2)) - \ || (a:mods[-2:-2] && a:kind == 1)) -endfu - -fu! s:SearchMember(ci, name, fullmatch, kind, returnAll, memberkind, ...) - let result = [[], [], []] - - if a:kind != 13 - for m in (a:0 > 0 && a:1 ? [] : get(a:ci, 'fields', [])) + ((a:kind == 1 || a:kind == 2) ? get(a:ci, 'declared_fields', []) : []) - if empty(a:name) || (a:fullmatch ? m.n ==# a:name : m.n =~# '^' . a:name) - if s:CanAccess(m.m, a:kind) - call add(result[2], m) - endif - endif - endfor - - for m in (a:0 > 0 && a:1 ? [] : get(a:ci, 'methods', [])) + ((a:kind == 1 || a:kind == 2) ? get(a:ci, 'declared_methods', []) : []) - if empty(a:name) || (a:fullmatch ? m.n ==# a:name : m.n =~# '^' . a:name) - if s:CanAccess(m.m, a:kind) - call add(result[1], m) - endif - endif - endfor - endif - - if a:kind/10 != 0 - let types = get(a:ci, 'classes', []) - for t in types - if empty(a:name) || (a:fullmatch ? t[strridx(t, '.')+1:] ==# a:name : t[strridx(t, '.')+1:] =~# '^' . a:name) - if !has_key(s:cache, t) || !has_key(s:cache[t], 'flags') || a:kind == 1 || s:cache[t].flags[-1:] - call add(result[0], t) - endif - endif - endfor - endif - - " key `classpath` indicates it is a loaded class from classpath - " All public members of a loaded class are stored in current ci - if !has_key(a:ci, 'classpath') || (a:kind == 1 || a:kind == 2) - for i in get(a:ci, 'extends', []) - let ci = s:DoGetClassInfo(java_parser#type2Str(i)) - let members = s:SearchMember(ci, a:name, a:fullmatch, a:kind == 1 ? 2 : a:kind, a:returnAll, a:memberkind) - let result[0] += members[0] - let result[1] += members[1] - let result[2] += members[2] - endfor - endif - return result -endfu - - -" generate member list {{{2 - -fu! s:DoGetFieldList(fields) - let s = '' - for field in a:fields - let s .= "{'kind':'" . (s:IsStatic(field.m) ? "F" : "f") . "','word':'" . field.n . "','menu':'" . field.t . "','dup':1}," - endfor - return s -endfu - -fu! s:DoGetMethodList(methods, ...) - let paren = a:0 == 0 || !a:1 ? '(' : '' - let s = '' - for method in a:methods - let s .= "{'kind':'" . (s:IsStatic(method.m) ? "M" : "m") . "','word':'" . method.n . paren . "','abbr':'" . method.n . "()','menu':'" . method.d . "','dup':'1'}," - endfor - return s -endfu - -" kind: -" 0 - for instance, 1 - this, 2 - super, 3 - class, 4 - array, 5 - method result, 6 - primitive type -" 11 - for type, with `class` and static member and nested types. -" 12 - for import static, no lparen for static methods -" 13 - for import or extends or implements, only nested types -" 20 - for package -fu! s:DoGetMemberList(ci, kind) - if type(a:ci) != type({}) || a:ci == {} - return [] - endif - - let s = a:kind == 11 ? "{'kind': 'C', 'word': 'class', 'menu': 'Class'}," : '' - - let members = s:SearchMember(a:ci, '', 1, a:kind, 1, 0, a:kind == 2) - - " add accessible member types - if a:kind / 10 != 0 - " Use dup here for member type can share name with field. - for class in members[0] - "for class in get(a:ci, 'classes', []) - let v = get(s:cache, class, {}) - if v == {} || v.flags[-1:] - let s .= "{'kind': 'C', 'word': '" . substitute(class, a:ci.name . '\.', '\1', '') . "','dup':1}," - endif - endfor - endif - - if a:kind != 13 - let fieldlist = [] - let sfieldlist = [] - for field in members[2] - "for field in get(a:ci, 'fields', []) - if s:IsStatic(field['m']) - call add(sfieldlist, field) - elseif a:kind / 10 == 0 - call add(fieldlist, field) - endif - endfor - - let methodlist = [] - let smethodlist = [] - for method in members[1] - if s:IsStatic(method['m']) - call add(smethodlist, method) - elseif a:kind / 10 == 0 - call add(methodlist, method) - endif - endfor - - if a:kind / 10 == 0 - let s .= s:DoGetFieldList(fieldlist) - let s .= s:DoGetMethodList(methodlist) - endif - let s .= s:DoGetFieldList(sfieldlist) - let s .= s:DoGetMethodList(smethodlist, a:kind == 12) - - let s = substitute(s, '\<' . a:ci.name . '\.', '', 'g') - let s = substitute(s, '\ 0 ? a:package . '*' : substitute(a:package, '\.', '/', 'g') . '/*' - let matchpattern = a:0 > 0 ? a:package : a:package . '[\\/]' - for f in split(globpath(join(pathes, ','), globpattern), "\n") - for path in pathes - let idx = matchend(f, escape(path, ' \') . '[\\/]\?\C' . matchpattern) - if idx != -1 - let name = (a:0 > 0 ? a:package : '') . strpart(f, idx) - if f[-5:] == '.java' - if !a:onlyPackages - call add(list, {'kind': 'C', 'word': name[:-6]}) - endif - elseif name =~ '^' . s:RE_IDENTIFIER . '$' && isdirectory(f) && f !~# 'CVS$' - call add(list, {'kind': 'P', 'word': name}) - endif - endif - endfor - endfor - return list -endfu -" }}} -"}}} -" vim:set fdm=marker sw=2 nowrap: diff --git a/vim/bundle/Vundle.vim b/vim/bundle/Vundle.vim index 0ee36b2..5f70ae6 160000 --- a/vim/bundle/Vundle.vim +++ b/vim/bundle/Vundle.vim @@ -1 +1 @@ -Subproject commit 0ee36b26e127cda512a8f2852a59e5a5f374c87f +Subproject commit 5f70ae6025e951f0154e3940d123138adffa4c88 diff --git a/vim/bundle/ctrlp.vim b/vim/bundle/ctrlp.vim index b5d3fe6..564176f 160000 --- a/vim/bundle/ctrlp.vim +++ b/vim/bundle/ctrlp.vim @@ -1 +1 @@ -Subproject commit b5d3fe66a58a13d2ff8b6391f4387608496a030f +Subproject commit 564176f01d7f3f7f8ab452ff4e1f5314de7b0981 diff --git a/vim/bundle/mirodark b/vim/bundle/mirodark deleted file mode 160000 index ed2a3c2..0000000 --- a/vim/bundle/mirodark +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ed2a3c2b07e10c208033feaa3e7956995d2923aa diff --git a/vim/bundle/molokai b/vim/bundle/molokai deleted file mode 160000 index db8ce13..0000000 --- a/vim/bundle/molokai +++ /dev/null @@ -1 +0,0 @@ -Subproject commit db8ce13b3737d3ddea8368498183d7c204a762eb diff --git a/vim/bundle/nerdtree b/vim/bundle/nerdtree index 0b44415..4ebbb53 160000 --- a/vim/bundle/nerdtree +++ b/vim/bundle/nerdtree @@ -1 +1 @@ -Subproject commit 0b44415a3302030b56755cc1135ca9ca57dc1ada +Subproject commit 4ebbb533c3faf2c480211db2b547972bb3b60f2b diff --git a/vim/bundle/undotree b/vim/bundle/undotree index 8ff701a..74874d9 160000 --- a/vim/bundle/undotree +++ b/vim/bundle/undotree @@ -1 +1 @@ -Subproject commit 8ff701a5bdb8d382431eb042e4faf3320883b020 +Subproject commit 74874d92d4bde3d026f2d0f3ff780b1787ba4e84 diff --git a/vim/bundle/vim-easymotion b/vim/bundle/vim-easymotion index 0806257..a21d447 160000 --- a/vim/bundle/vim-easymotion +++ b/vim/bundle/vim-easymotion @@ -1 +1 @@ -Subproject commit 0806257ca6432ac7beb75c4319dadf7f3ba9907b +Subproject commit a21d4474f0e9df7a721246e0a3b386068901965f diff --git a/vim/bundle/vim-multiple-cursors b/vim/bundle/vim-multiple-cursors index 146fe47..73a78c9 160000 --- a/vim/bundle/vim-multiple-cursors +++ b/vim/bundle/vim-multiple-cursors @@ -1 +1 @@ -Subproject commit 146fe47ee6b2faf90d6dc1232ef1858883d798bb +Subproject commit 73a78c926ad208bd1984e575ceece276d61a1404 diff --git a/vim/bundle/vim-perl b/vim/bundle/vim-perl index 5df5418..800481b 160000 --- a/vim/bundle/vim-perl +++ b/vim/bundle/vim-perl @@ -1 +1 @@ -Subproject commit 5df54184b9cf772527592e9db90b2ce7e4ca3a05 +Subproject commit 800481b537528f1951b52e03002f6aefbf4c0e4e diff --git a/vim/bundle/vim-startify b/vim/bundle/vim-startify index 314f0fb..7f38a76 160000 --- a/vim/bundle/vim-startify +++ b/vim/bundle/vim-startify @@ -1 +1 @@ -Subproject commit 314f0fb5f25b90eb5a0c332e3abcf95492d80eb9 +Subproject commit 7f38a761f63f6a3881f1cda10bc463bcb2f3b8c7