package com.googlecode.goclipse.ui.text;
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.Token;
import org.eclipse.jface.text.rules.WhitespaceRule;
import org.eclipse.jface.text.rules.WordRule;
import com.googlecode.goclipse.tooling.lexer.GoNumberLexingRule;
import com.googlecode.goclipse.ui.GoUIPreferenceConstants;
import melnorme.lang.ide.core_text.DefaultPredicateRule;
import melnorme.lang.ide.ui.text.AbstractLangScanner;
import melnorme.lang.ide.ui.text.coloring.TokenRegistry;
import melnorme.lang.tooling.parser.lexer.ILexingRule2;
import melnorme.lang.utils.parse.ICharacterReader;
import melnorme.utilbox.collections.ArrayList2;
public class GoScanner extends AbstractLangScanner {
public GoScanner(TokenRegistry tokenRegistry) {
super(tokenRegistry);
}
@Override
protected void initRules(ArrayList2<IRule> rules) {
// Add generic whitespace rule.
rules.add(new WhitespaceRule(new LangWhitespaceDetector()));
final IToken tkDefault = getToken(GoUIPreferenceConstants.DEFAULT);
WordRule wordRule = new WordRule(new JavaWordDetector(), tkDefault);
final IToken keyword = getToken(GoUIPreferenceConstants.KEYWORD);
final IToken primitive = getToken(GoUIPreferenceConstants.KW_NATIVE_TYPES);
final IToken builtinFunction = getToken(GoUIPreferenceConstants.BUILTIN_FUNCTION);
final IToken textToken = getToken(GoUIPreferenceConstants.DEFAULT);
setDefaultReturnToken(textToken);
// add tokens for each reserved word
wordRule.addWord("break", keyword);
wordRule.addWord("default", keyword);
wordRule.addWord("func", keyword);
wordRule.addWord("interface", keyword);
wordRule.addWord("select", keyword);
wordRule.addWord("case", keyword);
wordRule.addWord("defer", keyword);
wordRule.addWord("go", keyword);
wordRule.addWord("map", keyword);
wordRule.addWord("struct", keyword);
wordRule.addWord("chan", keyword);
wordRule.addWord("else", keyword);
wordRule.addWord("goto", keyword);
wordRule.addWord("package", keyword);
wordRule.addWord("switch", keyword);
wordRule.addWord("const", keyword);
wordRule.addWord("fallthrough", keyword);
wordRule.addWord("if", keyword);
wordRule.addWord("range", keyword);
wordRule.addWord("type", keyword);
wordRule.addWord("continue", keyword);
wordRule.addWord("for", keyword);
wordRule.addWord("import", keyword);
wordRule.addWord("return", keyword);
wordRule.addWord("var", keyword);
wordRule.addWord("iota", keyword);
wordRule.addWord("append", builtinFunction);
wordRule.addWord("cap", builtinFunction);
wordRule.addWord("close", builtinFunction);
wordRule.addWord("complex", builtinFunction);
wordRule.addWord("copy", builtinFunction);
wordRule.addWord("delete", builtinFunction);
wordRule.addWord("imag", builtinFunction);
wordRule.addWord("len", builtinFunction);
wordRule.addWord("make", builtinFunction);
wordRule.addWord("new", builtinFunction);
wordRule.addWord("panic", builtinFunction);
wordRule.addWord("print", builtinFunction);
wordRule.addWord("println", builtinFunction);
wordRule.addWord("real", builtinFunction);
wordRule.addWord("recover", builtinFunction);
final IToken value = getToken(GoUIPreferenceConstants.KW_LITERAL);
wordRule.addWord("nil", value);
wordRule.addWord("true", value);
wordRule.addWord("false", value);
wordRule.addWord("uint8", primitive);
wordRule.addWord("uint16", primitive);
wordRule.addWord("uint32", primitive);
wordRule.addWord("uint64", primitive);
wordRule.addWord("int8", primitive);
wordRule.addWord("int16", primitive);
wordRule.addWord("int32", primitive);
wordRule.addWord("int64", primitive);
wordRule.addWord("float32", primitive);
wordRule.addWord("float64", primitive);
wordRule.addWord("complex64", primitive);
wordRule.addWord("complex128", primitive);
wordRule.addWord("rune", primitive);
wordRule.addWord("byte", primitive);
wordRule.addWord("uint", primitive);
wordRule.addWord("int", primitive);
wordRule.addWord("uintptr", primitive);
wordRule.addWord("string", primitive);
wordRule.addWord("bool", primitive);
wordRule.addWord("error", primitive);
rules.add(wordRule);
rules.add(new LexingRule_RuleAdapter(new GoSubLexer(getToken(GoUIPreferenceConstants.NUMBER))));
rules.add(new GoOperatorRule(getToken(GoUIPreferenceConstants.OPERATOR)));
rules.add(new GoControlCharactersRule(getToken(GoUIPreferenceConstants.STRUCTURAL_SYMBOLS)));
}
protected final class GoSubLexer implements ILexingRule2<IToken> {
protected final GoNumberLexingRule numberRule = new GoNumberLexingRule();
protected final IToken numberToken;
public GoSubLexer(IToken numberToken) {
this.numberToken = numberToken;
}
@Override
public IToken doEvaluateToken(ICharacterReader subReader) {
if(numberRule.doEvaluate(subReader)) {
return numberToken;
}
return null;
}
}
public static class GoOperatorRule extends DefaultPredicateRule {
public GoOperatorRule(IToken token) {
super(token);
}
@Override
public IToken evaluate(ICharacterScanner scanner) {
int read = scanner.read();
if(read == ICharacterScanner.EOF) {
return Token.UNDEFINED;
}
switch (read) {
case '+': return currentOr('=', '+', scanner);
case '-': return currentOr('=', '-', scanner);
case '*': return currentOr('=', scanner);
case '/': return currentOr('=', scanner);
case '^': return currentOr('=', scanner);
case '!': return currentOr('=', scanner);
case '=': return currentOr('=', scanner);
case '%': return currentOr('=', scanner);
case '|': return currentOr('=', '|', scanner);
case '&':
if(consume('^', scanner)) {
return currentOr('=', scanner);
}
return currentOr('=', '&', scanner);
case '<':
if(consume('<', scanner)) {
return currentOr('=', scanner);
}
return currentOr('=', '-', scanner);
case '>':
if(consume('>', scanner)) {
return currentOr('=', scanner); // ">>" , ">>="
}
return currentOr('=', scanner);
case ':':
if(consume('=', scanner)) {
return getSuccessToken(); // ":="
}
// fall-through
default:
scanner.unread(); return Token.UNDEFINED;
}
}
}
public static class GoControlCharactersRule extends DefaultPredicateRule {
public GoControlCharactersRule(IToken token) {
super(token);
}
@Override
public IToken evaluate(ICharacterScanner scanner) {
int read = scanner.read();
if(read == ICharacterScanner.EOF) {
return Token.UNDEFINED;
}
switch (read) {
case ':':
case ';':
case '.':
case '(':
case ')':
case '[':
case ']':
case '{':
case '}':
return getSuccessToken();
default:
scanner.unread(); return Token.UNDEFINED;
}
}
}
}