aboutsummaryrefslogtreecommitdiff
path: root/files/.vim/autoload
diff options
context:
space:
mode:
authorAnton Bobov <abobov@gmail.com>2013-10-03 09:48:51 +0600
committerAnton Bobov <abobov@gmail.com>2013-10-03 09:53:41 +0600
commita909de07c5f982968cb8cd0f2101ac052f4a0034 (patch)
tree99111641ac662d8b437d885befe50ff1a3f3dbf9 /files/.vim/autoload
parentede4983c110a5947fa034857a5e37bdbb03ab49a (diff)
Vim plugins cleaning up.
Diffstat (limited to 'files/.vim/autoload')
-rw-r--r--files/.vim/autoload/Reflection.java670
-rw-r--r--files/.vim/autoload/java_parser.vim3500
-rw-r--r--files/.vim/autoload/javacomplete.vim2918
3 files changed, 0 insertions, 7088 deletions
diff --git a/files/.vim/autoload/Reflection.java b/files/.vim/autoload/Reflection.java
deleted file mode 100644
index 5452b0f..0000000
--- a/files/.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 <fangread@yahoo.com.cn>
- * 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/files/.vim/autoload/java_parser.vim b/files/.vim/autoload/java_parser.vim
deleted file mode 100644
index 5e1ec38..0000000
--- a/files/.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 <fangread@yahoo.com.cn>
-" 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 '<strange>'
- 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 '<error>'
- 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 '<error>'
- 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 '<error>'
- 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 = '<error>'
- 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 .= '<SEMI expected>'
- 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/files/.vim/autoload/javacomplete.vim b/files/.vim/autoload/javacomplete.vim
deleted file mode 100644
index becef53..0000000
--- a/files/.vim/autoload/javacomplete.vim
+++ /dev/null
@@ -1,2918 +0,0 @@
-" Vim completion script - hit 80% complete tasks
-" Version: 0.77.1
-" Language: Java
-" Maintainer: cheng fang <fangread@yahoo.com.cn>
-" Last Change: 2007-09-26
-" 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 =~# '\<static\s\+' ? s:CONTEXT_IMPORT_STATIC : s:CONTEXT_IMPORT
- let b:dotexpr = substitute(statement, '^\s*import\s\+\(static\s\+\)\?', '', '')
- else
- let b:context_type = s:CONTEXT_PACKAGE_DECL
- let b:dotexpr = substitute(statement, '\s*package\s\+', '', '')
- endif
-
- " String literal
- elseif statement =~ '"\s*\.\s*$'
- let b:dotexpr = substitute(statement, '\s*\.\s*$', '\.', '')
- return start - strlen(b:incomplete)
-
- else
- " type declaration NOTE: not supported generic yet.
- let idx_type = matchend(statement, '^\s*' . s:RE_TYPE_DECL)
- if idx_type != -1
- let b:dotexpr = strpart(statement, idx_type)
- " return if not after extends or implements
- if b:dotexpr !~ '^\(extends\|implements\)\s\+'
- return -1
- endif
- let b:context_type = s:CONTEXT_NEED_TYPE
- endif
-
- let b:dotexpr = s:ExtractCleanExpr(statement)
- endif
-
- " all cases: " java.ut|" or " java.util.|" or "ja|"
- let b:incomplete = strpart(b:dotexpr, strridx(b:dotexpr, '.')+1)
- let b:dotexpr = strpart(b:dotexpr, 0, strridx(b:dotexpr, '.')+1)
- return start - strlen(b:incomplete)
-
-
- " method parameters, treat methodname or 'new' as an incomplete word
- elseif statement =~ '(\s*$'
- " TODO: Need to exclude method declaration?
- let b:context_type = s:CONTEXT_METHOD_PARAM
- let pos = strridx(statement, '(')
- let s:padding = strpart(statement, pos+1)
- let start = start - (len(statement) - pos)
-
- let statement = substitute(statement, '\s*(\s*$', '', '')
-
- " new ClassName?
- let str = matchstr(statement, '\<new\s\+' . s:RE_QUALID . '$')
- if str != ''
- let str = substitute(str, '^new\s\+', '', '')
- if !s:IsKeyword(str)
- let b:incomplete = '+'
- let b:dotexpr = str
- return start - len(b:dotexpr)
- endif
-
- " normal method invocations
- else
- let pos = match(statement, '\s*' . s:RE_IDENTIFIER . '$')
- " case: "method(|)", "this(|)", "super(|)"
- if pos == 0
- let statement = substitute(statement, '^\s*', '', '')
- " treat "this" or "super" as a type name.
- if statement == 'this' || statement == 'super'
- let b:dotexpr = statement
- let b:incomplete = '+'
- return start - len(b:dotexpr)
-
- elseif !s:IsKeyword(statement)
- let b:incomplete = statement
- return start - strlen(b:incomplete)
- endif
-
- " case: "expr.method(|)"
- elseif statement[pos-1] == '.' && !s:IsKeyword(strpart(statement, pos))
- let b:dotexpr = s:ExtractCleanExpr(strpart(statement, 0, pos))
- let b:incomplete = strpart(statement, pos)
- return start - strlen(b:incomplete)
- endif
- endif
- endif
-
- return -1
- endif
-
-
- " Return list of matches.
-
- call s:WatchVariant('b:context_type: "' . b:context_type . '" b:incomplete: "' . b:incomplete . '" b:dotexpr: "' . b:dotexpr . '"')
- if b:dotexpr =~ '^\s*$' && b:incomplete =~ '^\s*$'
- return []
- endif
-
-
- let result = []
- if b:dotexpr !~ '^\s*$'
- if b:context_type == s:CONTEXT_AFTER_DOT
- let result = s:CompleteAfterDot(b:dotexpr)
- elseif b:context_type == s:CONTEXT_IMPORT || b:context_type == s:CONTEXT_IMPORT_STATIC || b:context_type == s:CONTEXT_PACKAGE_DECL || b:context_type == s:CONTEXT_NEED_TYPE
- let result = s:GetMembers(b:dotexpr[:-2])
- elseif b:context_type == s:CONTEXT_METHOD_PARAM
- if b:incomplete == '+'
- let result = s:GetConstructorList(b:dotexpr)
- else
- let result = s:CompleteAfterDot(b:dotexpr)
- endif
- endif
-
- " only incomplete word
- elseif b:incomplete !~ '^\s*$'
- " only need methods
- if b:context_type == s:CONTEXT_METHOD_PARAM
- let methods = s:SearchForName(b:incomplete, 0, 1)[1]
- call extend(result, eval('[' . s:DoGetMethodList(methods) . ']'))
-
- else
- let result = s:CompleteAfterWord(b:incomplete)
- endif
-
- " then no filter needed
- let b:incomplete = ''
- endif
-
-
- if len(result) > 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\<public\>' || 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), '\<new[ \t\r\n ]*$')
-
- return strpart(cmd, idx != -1 ? idx : pos+1)
-endfu
-
-fu! s:ParseExpr(expr)
- let items = []
- let s = 0
- " recognize ClassInstanceCreationExpr as a whole
- let e = matchend(a:expr, '^\s*new\s\+' . s:RE_QUALID . '\s*[([]')-1
- if e < 0
- let e = match(a:expr, '[.([]')
- endif
- let isparen = 0
- while e >= 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, '\<new\s\+' . s:RE_QUALID . '\s*(\s*$')
- if idx >= 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('\<import\s*=[''"]', 'W')
- if (lnum == 0)
- break
- endif
-
- let str = getline(lnum)
- if str =~ '<%\s*@\s*page\>' || str =~ '<jsp:\s*directive.page\>'
- 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('\<import\>', '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]\+\)\?\(\<class\>\|\<interface\>\)[ \t\n\r]\+HelloWorld[^a-zA-Z0-9_$]', 'W')
-" echo substitute(getline('.'), '.*\(\(public\|protected\|private\)[ \t\n\r]\+\)\?\(\(static\)[ \t\n\r]\+\)\?\(\<class\>\|\<interface\>\)\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('\(\<class\>\|\<interface\>\)[ \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, '.*\(\<class\>\|\<interface\>\)\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('\(\<class\C\>\|\<interface\C\>\|\<enum\C\>\)[ \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, '.*\(\<class\>\|\<interface\>\)\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('<cword>')
-
- 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()
- 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
- 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('<cword>')
- 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('<cword>')
- if cword == a:name
- return 0
- endif
- if getline('.')[col('.')-1] == '{'
- normal %
- endif
- endwhile
- endif
- return 1
-endfu
-"nmap <F8> :call <SID>Searchdecl(expand('<cword>'))<CR>
-
-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\<public\>' || 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 =~ '\<static\>'
- 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 =~ '\<static\>'
- 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, '\<java\.lang\.', '', 'g')
- let s = substitute(s, '\<\(public\|static\|synchronized\|transient\|volatile\|final\|strictfp\|serializable\|native\)\s\+', '', 'g')
- endif
- return eval('[' . s . ']')
-endfu
-
-" interface {{{2
-
-function! s:GetMemberList(class)
- if s:IsBuiltinType(a:class)
- return []
- endif
-
- return s:DoGetMemberList(s:DoGetClassInfo(a:class), 0)
-endfunction
-
-fu! s:GetStaticMemberList(class)
- return s:DoGetMemberList(s:DoGetClassInfo(a:class), 11)
-endfu
-
-function! s:GetConstructorList(class)
- let ci = s:DoGetClassInfo(a:class)
- if empty(ci)
- return []
- endif
-
- let s = ''
- for ctor in get(ci, 'ctors', [])
- let s .= "{'kind': '+', 'word':'". a:class . "(','abbr':'" . ctor.d . "','dup':1},"
- endfor
-
- let s = substitute(s, '\<java\.lang\.', '', 'g')
- let s = substitute(s, '\<public\s\+', '', 'g')
- return eval('[' . s . ']')
-endfunction
-
-" Name can be a (simple or qualified) package name, or a (simple or qualified)
-" type name.
-fu! s:GetMembers(fqn, ...)
- let list = []
- let isClass = 0
-
- let v = s:DoGetInfoByReflection(a:fqn, '-E')
- if type(v) == type([])
- let list = v
- elseif type(v) == type({}) && v != {}
- if get(v, 'tag', '') == 'PACKAGE'
- if b:context_type == s:CONTEXT_IMPORT_STATIC || b:context_type == s:CONTEXT_IMPORT
- call add(list, {'kind': 'P', 'word': '*;'})
- endif
- if b:context_type != s:CONTEXT_PACKAGE_DECL
- for c in sort(get(v, 'classes', []))
- call add(list, {'kind': 'C', 'word': c})
- endfor
- endif
- for p in sort(get(v, 'subpackages', []))
- call add(list, {'kind': 'P', 'word': p})
- endfor
- else " elseif get(v, 'tag', '') == 'CLASSDEF'
- let isClass = 1
- let list += s:DoGetMemberList(v, b:context_type == s:CONTEXT_IMPORT || b:context_type == s:CONTEXT_NEED_TYPE ? 13 : b:context_type == s:CONTEXT_IMPORT_STATIC ? 12 : 11)
- endif
- endif
-
- if !isClass
- let list += s:DoGetPackageInfoInDirs(a:fqn, b:context_type == s:CONTEXT_PACKAGE_DECL)
- endif
-
- return list
-endfu
-
-" a:1 incomplete mode
-" return packages in classes directories or source pathes
-fu! s:DoGetPackageInfoInDirs(package, onlyPackages, ...)
- let list = []
-
- let pathes = s:GetSourceDirs(expand('%:p'))
- for path in s:GetClassDirs()
- if index(pathes, path) <= 0
- call add(pathes, path)
- endif
- endfor
-
- let globpattern = a:0 > 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: