Package ccw

Source Code of ccw.StaticScanContext

/*******************************************************************************
* Copyright (c) 2009 Laurent Petit.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*    Laurent PETIT - initial API and implementation
*******************************************************************************/

package ccw;

import java.util.HashMap;
import java.util.Map;

import ccw.editors.clojure.IScanContext;
import ccw.preferences.PreferenceConstants;
import ccw.util.ClojureInvoker;
import clojure.lang.Keyword;
import clojure.lang.RT;
import clojure.lang.Var;

public class StaticScanContext implements IScanContext {
  private Map<String,Keyword> clojureSymbolTypesCache = new HashMap<String, Keyword>();
 
  // TODO this is to ensure that ccw.debug.clientrepl is launched ...
  private ClojureInvoker clientrepl = ClojureInvoker.newInvoker(CCWPlugin.getDefault(), "ccw.debug.clientrepl");
 
  private final Var coreSymbolType = RT.var("ccw.debug.clientrepl", "core-symbol-type");
 
  private boolean isJavaIdentifier(String s) {
    assert s != null && s.length() > 0;
   
    if (!Character.isJavaIdentifierStart(s.charAt(0))) {
      return false;
    }
    for (int i = 1; i < s.length(); i++) {
      if (!Character.isJavaIdentifierPart(s.charAt(i))) {
        return false;
      }
    }
    return true;
  }
 
  private boolean isEarmuffedVar(String symbol) {
    return (!symbol.equals("*")
         &&
        symbol.startsWith("*") || symbol.contains("/*"))
         &&
         symbol.endsWith("*");
  }
 
  public Keyword getSymbolType(String symbol, boolean isCallableSymbol) {
    assert symbol != null && symbol.length() > 0;
   
    if (isEarmuffedVar(symbol)) {
      return isCallableSymbol ? PreferenceConstants.callableGLOBAL_VAR_Token : PreferenceConstants.GLOBAL_VAR_Token;
    }
   
    if (symbol.startsWith("."&&  symbol.length() > 1) {
      if (isJavaIdentifier(symbol.substring(1))) {
        return isCallableSymbol ? PreferenceConstants.callableJAVA_INSTANCE_METHOD_Token : PreferenceConstants.JAVA_INSTANCE_METHOD_Token;
      }
    }
   
    // This code must appear after the test for JAVA_INSTANCE_METHOD, or a bug in it would mask
    // any attempt to guess a java instance method
    int from;
    int foundIndex = -1;
    int letterAfterPointIndex = 0;
    do {
      letterAfterPointIndex = foundIndex + 1;
      if ( (letterAfterPointIndex < symbol.length()) && Character.isUpperCase(symbol.charAt(letterAfterPointIndex)) ) {
        if (symbol.substring(letterAfterPointIndex + 1).contains("/")) {
          return isCallableSymbol ? PreferenceConstants.callableJAVA_STATIC_METHOD_Token : PreferenceConstants.JAVA_STATIC_METHOD_Token;
        } else {
          return isCallableSymbol ? PreferenceConstants.callableJAVA_CLASS_Token : PreferenceConstants.JAVA_CLASS_Token;
        }
      } else {
        from = letterAfterPointIndex;
      }
    } while ((from < symbol.length()) && (foundIndex = symbol.indexOf('.', from)) > 0);
    /*
     TODO activate this possibility via a preference to get a visible bootstrap gain
    if (isCallableSymbol) // 2.7 sec.
      return PreferenceConstants.RAW_SYMBOL_Token;
    else
      return PreferenceConstants.callable_RAW_SYMBOL_Token;
    */
    if (clojureSymbolTypesCache.containsKey(symbol)) {
      return getCallableOrNonCallable(clojureSymbolTypesCache.get(symbol), isCallableSymbol);
    } else {
      Keyword symbolType =  (Keyword) coreSymbolType.invoke(symbol)
 
      if (symbolType == null) {
        clojureSymbolTypesCache.put(symbol, PreferenceConstants.RAW_SYMBOL_Token);
        return getCallableOrNonCallable(PreferenceConstants.RAW_SYMBOL_Token, isCallableSymbol);
      } else {
        try {
          clojureSymbolTypesCache.put(symbol, symbolType);
          return getCallableOrNonCallable(symbolType, isCallableSymbol);
        } catch (IllegalArgumentException e) {
          CCWPlugin.logError("The clojure code returned an invalid symbolType value:'" + symbolType + "' for enumeration SymbolType", e);
          return null;
        }
      }
    }
   
  }
 
  private static final Map<Keyword, Keyword> symbolToCallable = new HashMap<Keyword, Keyword>() {
    {
      put(PreferenceConstants.RAW_SYMBOL_Token, PreferenceConstants.callable_RAW_SYMBOL_Token);
      put(PreferenceConstants.FUNCTION_Token, PreferenceConstants.callableFUNCTION_Token);
      put(PreferenceConstants.MACRO_Token, PreferenceConstants.callableMACRO_Token);
      put(PreferenceConstants.SPECIAL_FORM_Token, PreferenceConstants.callableSPECIAL_FORM_Token);
    }
  };
 
  private Keyword getCallableOrNonCallable(Keyword symbolKeyword, boolean isCallableSymbol) {
    if (isCallableSymbol) {
      Keyword callableFlavor = symbolToCallable.get(symbolKeyword);
      if (callableFlavor != null) {
        return callableFlavor;
      } else {
        return symbolKeyword;
      }
    } else {
      return symbolKeyword;
    }
  }
     
}
TOP

Related Classes of ccw.StaticScanContext

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.