blob: c2763d7a5abd3b7d233ba90405b57ed520592694 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2008 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Philippe Ombredanne <pombredanne@nexb.com> - https://bugs.eclipse.org/bugs/show_bug.cgi?id=150989
* Anton Leherbauer (Wind River Systems) - [misc] Allow custom token for WhitespaceRule - https://bugs.eclipse.org/bugs/show_bug.cgi?id=251224
*******************************************************************************/
package org.eclipse.e4.tools.emf.ui.script.js.text.scanners;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.e4.tools.emf.ui.script.js.ResourceProvider;
import org.eclipse.e4.tools.services.IResourcePool;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.rules.ICharacterScanner;
import org.eclipse.jface.text.rules.IRule;
import org.eclipse.jface.text.rules.IToken;
import org.eclipse.jface.text.rules.SingleLineRule;
import org.eclipse.jface.text.rules.Token;
import org.eclipse.jface.text.rules.WhitespaceRule;
/**
* A Java code scanner.
*/
public final class JavaScriptCodeScanner extends AbstractJavaScanner {
/**
* Rule to detect java operators.
*
* @since 3.0
*/
private static final class OperatorRule implements IRule {
/** Java operators */
private final char[] JAVA_OPERATORS= { ';', '.', '=', '/', '\\', '+', '-', '*', '<', '>', ':', '?', '!', ',', '|', '&', '^', '%', '~'};
/** Token to return for this rule */
private final IToken fToken;
/**
* Creates a new operator rule.
*
* @param token Token to use for this rule
*/
public OperatorRule(IToken token) {
fToken= token;
}
/**
* Is this character an operator character?
*
* @param character Character to determine whether it is an operator character
* @return <code>true</code> iff the character is an operator, <code>false</code> otherwise.
*/
public boolean isOperator(char character) {
for (int index= 0; index < JAVA_OPERATORS.length; index++) {
if (JAVA_OPERATORS[index] == character)
return true;
}
return false;
}
/*
* @see org.eclipse.jface.text.rules.IRule#evaluate(org.eclipse.jface.text.rules.ICharacterScanner)
*/
@Override
public IToken evaluate(ICharacterScanner scanner) {
int character= scanner.read();
if (isOperator((char) character)) {
do {
character= scanner.read();
} while (isOperator((char) character));
scanner.unread();
return fToken;
} else {
scanner.unread();
return Token.UNDEFINED;
}
}
}
/**
* Rule to detect java brackets.
*
* @since 3.3
*/
private static final class BracketRule implements IRule {
/** Java brackets */
private final char[] JAVA_BRACKETS= { '(', ')', '{', '}', '[', ']' };
/** Token to return for this rule */
private final IToken fToken;
/**
* Creates a new bracket rule.
*
* @param token Token to use for this rule
*/
public BracketRule(IToken token) {
fToken= token;
}
/**
* Is this character a bracket character?
*
* @param character Character to determine whether it is a bracket character
* @return <code>true</code> iff the character is a bracket, <code>false</code> otherwise.
*/
public boolean isBracket(char character) {
for (int index= 0; index < JAVA_BRACKETS.length; index++) {
if (JAVA_BRACKETS[index] == character)
return true;
}
return false;
}
/*
* @see org.eclipse.jface.text.rules.IRule#evaluate(org.eclipse.jface.text.rules.ICharacterScanner)
*/
@Override
public IToken evaluate(ICharacterScanner scanner) {
int character= scanner.read();
if (isBracket((char) character)) {
do {
character= scanner.read();
} while (isBracket((char) character));
scanner.unread();
return fToken;
} else {
scanner.unread();
return Token.UNDEFINED;
}
}
}
// private static class VersionedWordMatcher extends CombinedWordRule.WordMatcher implements ISourceVersionDependent {
//
// private final IToken fDefaultToken;
// private final String fVersion;
// private boolean fIsVersionMatch;
//
// public VersionedWordMatcher(IToken defaultToken, String version, String currentVersion) {
// fDefaultToken= defaultToken;
// fVersion= version;
// setSourceVersion(currentVersion);
// }
//
// /*
// * @see org.eclipse.jdt.internal.ui.text.ISourceVersionDependent#setSourceVersion(java.lang.String)
// */
// public void setSourceVersion(String version) {
// fIsVersionMatch= fVersion.compareTo(version) <= 0;
// }
//
// /*
// * @see org.eclipse.jdt.internal.ui.text.CombinedWordRule.WordMatcher#evaluate(org.eclipse.jface.text.rules.ICharacterScanner, org.eclipse.jdt.internal.ui.text.CombinedWordRule.CharacterBuffer)
// */
// public IToken evaluate(ICharacterScanner scanner, CombinedWordRule.CharacterBuffer word) {
// IToken token= super.evaluate(scanner, word);
//
// if (fIsVersionMatch || token.isUndefined())
// return token;
//
// return fDefaultToken;
// }
// }
// /**
// * An annotation rule matches the '@' symbol, any following whitespace and
// * optionally a following <code>interface</code> keyword.
// *
// * It does not match if there is a comment between the '@' symbol and
// * the identifier. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=82452
// *
// * @since 3.1
// */
// private static class AnnotationRule implements IRule, ISourceVersionDependent {
// /**
// * A resettable scanner supports marking a position in a scanner and
// * unreading back to the marked position.
// */
// private static final class ResettableScanner implements ICharacterScanner {
// private final ICharacterScanner fDelegate;
// private int fReadCount;
//
// /**
// * Creates a new resettable scanner that will forward calls
// * to <code>scanner</code>, but store a marked position.
// *
// * @param scanner the delegate scanner
// */
// public ResettableScanner(final ICharacterScanner scanner) {
// fDelegate= scanner;
// mark();
// }
//
// /*
// * @see org.eclipse.jface.text.rules.ICharacterScanner#getColumn()
// */
// public int getColumn() {
// return fDelegate.getColumn();
// }
//
// /*
// * @see org.eclipse.jface.text.rules.ICharacterScanner#getLegalLineDelimiters()
// */
// public char[][] getLegalLineDelimiters() {
// return fDelegate.getLegalLineDelimiters();
// }
//
// /*
// * @see org.eclipse.jface.text.rules.ICharacterScanner#read()
// */
// public int read() {
// int ch= fDelegate.read();
// if (ch != ICharacterScanner.EOF)
// fReadCount++;
// return ch;
// }
//
// /*
// * @see org.eclipse.jface.text.rules.ICharacterScanner#unread()
// */
// public void unread() {
// if (fReadCount > 0)
// fReadCount--;
// fDelegate.unread();
// }
//
// /**
// * Marks an offset in the scanned content.
// */
// public void mark() {
// fReadCount= 0;
// }
//
// /**
// * Resets the scanner to the marked position.
// */
// public void reset() {
// while (fReadCount > 0)
// unread();
//
// while (fReadCount < 0)
// read();
// }
// }
//
// private final IWhitespaceDetector fWhitespaceDetector= new JavaScriptWhitespaceDetector();
// private final IWordDetector fWordDetector= new JavaScriptWordDetector();
// private final IToken fInterfaceToken;
// private final IToken fAtToken;
// private final String fVersion;
// private boolean fIsVersionMatch;
//
// /**
// * Creates a new rule.
// *
// * @param interfaceToken the token to return if
// * <code>'@\s*interface'</code> is matched
// * @param atToken the token to return if <code>'@'</code>
// * is matched, but not <code>'@\s*interface'</code>
// * @param version the lowest <code>JavaCore.COMPILER_SOURCE</code>
// * version that this rule is enabled
// * @param currentVersion the current
// * <code>JavaCore.COMPILER_SOURCE</code> version
// */
// public AnnotationRule(IToken interfaceToken, Token atToken, String version, String currentVersion) {
// fInterfaceToken= interfaceToken;
// fAtToken= atToken;
// fVersion= version;
// setSourceVersion(currentVersion);
// }
//
// /*
// * @see org.eclipse.jface.text.rules.IRule#evaluate(org.eclipse.jface.text.rules.ICharacterScanner)
// */
// public IToken evaluate(ICharacterScanner scanner) {
// if (!fIsVersionMatch)
// return Token.UNDEFINED;
//
// ResettableScanner resettable= new ResettableScanner(scanner);
// if (resettable.read() == '@')
// return readAnnotation(resettable);
//
// resettable.reset();
// return Token.UNDEFINED;
// }
//
// private IToken readAnnotation(ResettableScanner scanner) {
// scanner.mark();
// skipWhitespace(scanner);
// if (readInterface(scanner)) {
// return fInterfaceToken;
// } else {
// scanner.reset();
// return fAtToken;
// }
// }
//
// private boolean readInterface(ICharacterScanner scanner) {
// int ch= scanner.read();
// int i= 0;
// while (i < INTERFACE.length() && INTERFACE.charAt(i) == ch) {
// i++;
// ch= scanner.read();
// }
// if (i < INTERFACE.length())
// return false;
//
// if (fWordDetector.isWordPart((char) ch))
// return false;
//
// if (ch != ICharacterScanner.EOF)
// scanner.unread();
//
// return true;
// }
//
// private boolean skipWhitespace(ICharacterScanner scanner) {
// while (fWhitespaceDetector.isWhitespace((char) scanner.read())) {
// // do nothing
// }
//
// scanner.unread();
// return true;
// }
//
// /*
// * @see org.eclipse.jdt.internal.ui.text.ISourceVersionDependent#setSourceVersion(java.lang.String)
// */
// public void setSourceVersion(String version) {
// fIsVersionMatch= fVersion.compareTo(version) <= 0;
// }
//
// }
// private static final String SOURCE_VERSION= JavaCore.COMPILER_SOURCE;
/*static String[] fgKeywords= {
"abstract", //$NON-NLS-1$
"break", //$NON-NLS-1$
"case", "catch", "class", "const", "continue", //$NON-NLS-5$ //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$
"default", "do", //$NON-NLS-2$ //$NON-NLS-1$
"else", "extends", //$NON-NLS-2$ //$NON-NLS-1$
"final", "finally", "for", //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$
"goto", //$NON-NLS-1$
"if", "implements", "import", "instanceof", "interface", //$NON-NLS-5$ //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$
"native", "new", //$NON-NLS-2$ //$NON-NLS-1$
"package", "private", "protected", "public", //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$
"static", "super", "switch", "synchronized", //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$
"this", "throw", "throws", "transient", "try", //$NON-NLS-5$ //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$
"volatile", //$NON-NLS-1$
"while" //$NON-NLS-1$
};*/
static String[] fgKeywords= {
"break",
"case",
"catch",
"continue",
"debugger",
"default",
"delete",
"do",
"else",
"finally",
"for",
"function",
"if",
"in",
"instanceof",
"new",
// "return",
"switch",
"this",
"throw",
"try",
"typeof",
"var",
"void",
"while",
"with",
"class",
"enum",
"export",
"extends",
"import",
"super"
};
// private static final String INTERFACE= "interface"; //$NON-NLS-1$
private static final String RETURN= "return"; //$NON-NLS-1$
// private static String[] fgJava14Keywords= { "assert" }; //$NON-NLS-1$
// private static String[] fgJava15Keywords= { "enum" }; //$NON-NLS-1$
private static String[] fgTypes= { "void", "boolean", "char", "byte", "short", "strictfp", "int", "long", "float", "double" }; //$NON-NLS-1$ //$NON-NLS-5$ //$NON-NLS-7$ //$NON-NLS-6$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-2$
private static String[] fgConstants= { "false", "null", "true" }; //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$
// private static final String ANNOTATION_BASE_KEY= PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_PREFIX + SemanticHighlightings.ANNOTATION;
// private static final String ANNOTATION_COLOR_KEY= "COLOR_org.eclipse.e4.tools.emf.ui.script.js." + ANNOTATION_BASE_KEY + PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_COLOR_SUFFIX;
private static String[] fgTokenProperties= {
ResourceProvider.JAVA_KEYWORD,
ResourceProvider.JAVA_STRING,
ResourceProvider.JAVA_DEFAULT,
ResourceProvider.JAVA_KEYWORD_RETURN,
ResourceProvider.JAVA_OPERATOR,
ResourceProvider.JAVA_BRACKET/*,
ANNOTATION_COLOR_KEY,*/
};
// private List<ISourceVersionDependent> fVersionDependentRules= new ArrayList<ISourceVersionDependent>(3);
/**
* Creates a Java code scanner
*
* @param manager the color manager
* @param store the preference store
*/
public JavaScriptCodeScanner(IResourcePool manager, IPreferenceStore store) {
super(manager, store);
initialize();
}
/*
* @see AbstractJavaScanner#getTokenProperties()
*/
@Override
protected String[] getTokenProperties() {
return fgTokenProperties;
}
/*
* @see AbstractJavaScanner#createRules()
*/
@Override
protected List<IRule> createRules() {
List<IRule> rules= new ArrayList<IRule>();
// Add rule for character constants.
Token token= getToken(ResourceProvider.JAVA_STRING);
rules.add(new SingleLineRule("'", "'", token, '\\')); //$NON-NLS-2$ //$NON-NLS-1$
Token defaultToken= getToken(ResourceProvider.JAVA_DEFAULT);
// Add generic whitespace rule.
rules.add(new WhitespaceRule(new JavaScriptWhitespaceDetector(), defaultToken));
// String version= getPreferenceStore().getString(SOURCE_VERSION);
// // Add JLS3 rule for /@\s*interface/ and /@\s*\w+/
// token= getToken(ANNOTATION_COLOR_KEY);
// AnnotationRule atInterfaceRule= new AnnotationRule(getToken(IJavaScriptColorConstants.JAVA_KEYWORD), token, JavaCore.VERSION_1_5, version);
// rules.add(atInterfaceRule);
// fVersionDependentRules.add(atInterfaceRule);
//
// // Add word rule for new keywords, see bug 4077
JavaScriptWordDetector wordDetector= new JavaScriptWordDetector();
CombinedWordRule combinedWordRule= new CombinedWordRule(wordDetector, defaultToken);
//
// VersionedWordMatcher j14Matcher= new VersionedWordMatcher(defaultToken, JavaCore.VERSION_1_4, version);
//
// token= getToken(IJavaScriptColorConstants.JAVA_KEYWORD);
// for (int i=0; i<fgJava14Keywords.length; i++)
// j14Matcher.addWord(fgJava14Keywords[i], token);
//
// combinedWordRule.addWordMatcher(j14Matcher);
// fVersionDependentRules.add(j14Matcher);
//
// VersionedWordMatcher j15Matcher= new VersionedWordMatcher(defaultToken, JavaCore.VERSION_1_5, version);
//
// token= getToken(IJavaScriptColorConstants.JAVA_KEYWORD);
// for (int i=0; i<fgJava15Keywords.length; i++)
// j15Matcher.addWord(fgJava15Keywords[i], token);
//
// combinedWordRule.addWordMatcher(j15Matcher);
// fVersionDependentRules.add(j15Matcher);
// Add rule for operators
token= getToken(ResourceProvider.JAVA_OPERATOR);
rules.add(new OperatorRule(token));
// Add rule for brackets
token= getToken(ResourceProvider.JAVA_BRACKET);
rules.add(new BracketRule(token));
// Add word rule for keyword 'return'.
CombinedWordRule.WordMatcher returnWordRule= new CombinedWordRule.WordMatcher();
token= getToken(ResourceProvider.JAVA_KEYWORD_RETURN);
returnWordRule.addWord(RETURN, token);
combinedWordRule.addWordMatcher(returnWordRule);
// Add word rule for keywords, types, and constants.
CombinedWordRule.WordMatcher wordRule= new CombinedWordRule.WordMatcher();
token= getToken(ResourceProvider.JAVA_KEYWORD);
for (int i=0; i<fgKeywords.length; i++)
wordRule.addWord(fgKeywords[i], token);
for (int i=0; i<fgTypes.length; i++)
wordRule.addWord(fgTypes[i], token);
for (int i=0; i<fgConstants.length; i++)
wordRule.addWord(fgConstants[i], token);
combinedWordRule.addWordMatcher(wordRule);
rules.add(combinedWordRule);
setDefaultReturnToken(defaultToken);
return rules;
}
// /*
// * @see org.eclipse.jdt.internal.ui.text.AbstractJavaScanner#getBoldKey(java.lang.String)
// */
// protected String getBoldKey(String colorKey) {
// if ((ANNOTATION_COLOR_KEY).equals(colorKey))
// return ANNOTATION_BASE_KEY + PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_BOLD_SUFFIX;
// return super.getBoldKey(colorKey);
// }
//
// /*
// * @see org.eclipse.jdt.internal.ui.text.AbstractJavaScanner#getItalicKey(java.lang.String)
// */
// protected String getItalicKey(String colorKey) {
// if ((ANNOTATION_COLOR_KEY).equals(colorKey))
// return ANNOTATION_BASE_KEY + PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_ITALIC_SUFFIX;
// return super.getItalicKey(colorKey);
// }
//
// /*
// * @see org.eclipse.jdt.internal.ui.text.AbstractJavaScanner#getStrikethroughKey(java.lang.String)
// */
// protected String getStrikethroughKey(String colorKey) {
// if ((ANNOTATION_COLOR_KEY).equals(colorKey))
// return ANNOTATION_BASE_KEY + PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_STRIKETHROUGH_SUFFIX;
// return super.getStrikethroughKey(colorKey);
// }
//
// /*
// * @see org.eclipse.jdt.internal.ui.text.AbstractJavaScanner#getUnderlineKey(java.lang.String)
// */
// protected String getUnderlineKey(String colorKey) {
// if ((ANNOTATION_COLOR_KEY).equals(colorKey))
// return ANNOTATION_BASE_KEY + PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_UNDERLINE_SUFFIX;
// return super.getUnderlineKey(colorKey);
// }
//
// /*
// * @see AbstractJavaScanner#affectsBehavior(PropertyChangeEvent)
// */
// public boolean affectsBehavior(PropertyChangeEvent event) {
// return event.getProperty().equals(SOURCE_VERSION) || super.affectsBehavior(event);
// }
//
// /*
// * @see AbstractJavaScanner#adaptToPreferenceChange(PropertyChangeEvent)
// */
// public void adaptToPreferenceChange(PropertyChangeEvent event) {
//
// if (event.getProperty().equals(SOURCE_VERSION)) {
// Object value= event.getNewValue();
//
// if (value instanceof String) {
// String s= (String) value;
//
// for (Iterator<ISourceVersionDependent> it= fVersionDependentRules.iterator(); it.hasNext();) {
// ISourceVersionDependent dependent= (ISourceVersionDependent) it.next();
// dependent.setSourceVersion(s);
// }
// }
//
// } else if (super.affectsBehavior(event)) {
// super.adaptToPreferenceChange(event);
// }
// }
}