blob: e68bcca03e0e023aef8bba2e77587b512e4cd02b [file] [log] [blame]
/**********************************************************************
* Copyright (c) 2002,2003 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* QNX Software Systems - Initial API and implementation
***********************************************************************/
package org.eclipse.cdt.make.internal.ui.text.makefile;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.cdt.make.internal.ui.text.IMakefileColorManager;
import org.eclipse.jface.text.TextAttribute;
import org.eclipse.jface.text.rules.EndOfLineRule;
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.IWhitespaceDetector;
import org.eclipse.jface.text.rules.RuleBasedScanner;
import org.eclipse.jface.text.rules.Token;
import org.eclipse.jface.text.rules.WhitespaceRule;
import org.eclipse.jface.text.rules.WordRule;
public class MakefileCodeScanner extends RuleBasedScanner {
private final static String[] keywords = { "define", "endef", "ifdef", "ifndef", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
"ifeq", "ifneq", "else", "endif", "include", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
"-include", "sinclude", "override", "endef", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
"export", "unexport", "vpath" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
};
private final static String[] functions = { "subst", "patsubst", "strip", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
"findstring", "filter", "sort", "dir", "notdir", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
"suffix", "basename", "addsuffix", "addprefix", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
"join", "word", "words", "wordlist", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
"firstword", "wildcard", "error", "warning", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
"shell", "origin", "foreach", "call" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
};
/**
* Constructor for MakefileCodeScanner
*/
public MakefileCodeScanner(IMakefileColorManager provider) {
super();
IToken keyword = new Token(new TextAttribute(provider.getColor(IMakefileColorManager.MAKE_KEYWORD)));
IToken function = new Token(new TextAttribute(provider.getColor(IMakefileColorManager.MAKE_FUNCTION)));
IToken comment = new Token(new TextAttribute(provider.getColor(IMakefileColorManager.MAKE_COMMENT)));
IToken macro = new Token(new TextAttribute(provider.getColor(IMakefileColorManager.MAKE_MACRO_VAR)));
IToken other = new Token(new TextAttribute(provider.getColor(IMakefileColorManager.MAKE_DEFAULT)));
List rules = new ArrayList();
// Add rule for single line comments.
rules.add(new EndOfLineRule("#", comment, '\\')); //$NON-NLS-1$
// Add generic whitespace rule.
rules.add(new WhitespaceRule(new IWhitespaceDetector() {
public boolean isWhitespace(char character) {
return Character.isWhitespace(character);
}
}));
// Add word rule for keywords, types, and constants.
WordRule wordRule = new WordRule(new MakefileWordDetector(), other);
for (int i = 0; i < keywords.length; i++)
wordRule.addWord(keywords[i], keyword);
for (int i = 0; i < functions.length; i++)
wordRule.addWord(functions[i], function);
rules.add(wordRule);
//rules.add(new PatternRule("$(", ")", macro, '\\', true)); //$NON-NLS-1$ //$NON-NLS-2$
rules.add(new MakefileSimpleMacroRule(macro)); //$NON-NLS-1$ //$NON-NLS-2$
rules.add(new MacroRule(macro, other));
setDefaultReturnToken(other);
IRule[] result = new IRule[rules.size()];
rules.toArray(result);
setRules(result);
}
private class MacroRule implements IRule {
private static final int INIT_STATE = 0;
private static final int VAR_STATE = 1;
private static final int END_VAR_STATE = 2;
private static final int EQUAL_STATE = 3;
private static final int FINISH_STATE = 4;
private static final int ERROR_STATE = 5;
private IToken token;
private StringBuffer buffer = new StringBuffer();
protected IToken defaultToken;
public MacroRule(IToken token, IToken defaultToken) {
this.token = token;
this.defaultToken = defaultToken;
}
public IToken evaluate(ICharacterScanner scanner) {
int state = INIT_STATE;
buffer.setLength(0);
boolean bTwoCharsAssign = false;
for (int c = scanner.read(); c != ICharacterScanner.EOF; c = scanner.read()) {
switch (state) {
case INIT_STATE :
if (c != '\n' && Character.isWhitespace((char) c))
break;
if (isValidCharacter(c))
state = VAR_STATE;
else
state = ERROR_STATE;
break;
case VAR_STATE :
if (isValidCharacter(c))
break;
case END_VAR_STATE :
if (c != '\n' && Character.isWhitespace((char) c))
state = END_VAR_STATE;
else if (c == ':' || c == '+') {
bTwoCharsAssign = true;
state = EQUAL_STATE;
} else if (c == '=')
state = FINISH_STATE;
else {
if (state == END_VAR_STATE)
scanner.unread(); // Return back to the space
state = ERROR_STATE;
}
break;
case EQUAL_STATE :
if (c == '=')
state = FINISH_STATE;
else
state = ERROR_STATE;
break;
case FINISH_STATE :
break;
default :
break;
}
if (state >= FINISH_STATE)
break;
buffer.append((char) c);
}
scanner.unread();
if (state == FINISH_STATE) {
if (bTwoCharsAssign)
scanner.unread();
return token;
}
if (defaultToken.isUndefined())
unreadBuffer(scanner);
return Token.UNDEFINED;
}
/**
* Returns the characters in the buffer to the scanner.
*
* @param scanner the scanner to be used
*/
protected void unreadBuffer(ICharacterScanner scanner) {
for (int i = buffer.length() - 1; i >= 0; i--)
scanner.unread();
}
protected boolean isValidCharacter(int c) {
char c0 = (char) c;
return Character.isLetterOrDigit(c0) || (c0 == '_');
}
}
}