blob: a04312e9f424b8df0d5fbe96725d4ae31fec9e4a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.css.lib;
import java.util.ArrayList;
import java.util.List;
import org.antlr.runtime.*;
import org.netbeans.modules.css.lib.api.ProblemDescription;
import org.netbeans.modules.css.lib.api.ProblemDescription.Type;
import org.openide.util.NbBundle;
import static org.netbeans.modules.css.lib.Bundle.*;
/**
* Note: Funny aspect of the ANTLR lexer is that it doesn't create any kind of
* error tokens. So if there's a character in the input which cannot be properly
* made a part of a token it is simply skipped. The result is that the sequence
* of tokens is not continuous and there might be "holes".
*
* @author marekfukala
*/
public class ExtCss3Lexer extends Css3Lexer {
private List<ProblemDescription> problems = new ArrayList<>();
static boolean isLessSource_unit_tests = false;
static boolean isScssSource_unit_tests = false;
private boolean isLessSource = isLessSource_unit_tests;
private boolean isScssSource = isScssSource_unit_tests;
public ExtCss3Lexer(CharStream input, RecognizerSharedState state) {
super(input, state);
}
public ExtCss3Lexer(CharStream input) {
super(input);
}
public ExtCss3Lexer(CharSequence charSequence, String mimeType) {
this(charSequence);
if(mimeType != null) {
this.isLessSource = mimeType.equals("text/less");
this.isScssSource = mimeType.equals("text/scss");
}
}
/**
* Preferred constructor.
*
* Make the Css3Lexer case insensitive by default - the characters passed to
* the lexer are converted to upper case. The token images are in the
* original case though.
*/
public ExtCss3Lexer(CharSequence charSequence) {
this(new ANTLRStringStream(charSequence.toString()) {
@Override
public int LA(int i) {
if (i == 0) {
return 0; // undefined
}
if (i < 0) {
i++; // e.g., translate LA(-1) to use offset 0
}
if ((p + i - 1) >= n) {
return CharStream.EOF;
}
return Character.toUpperCase(data[p + i - 1]);
}
});
}
@Override
//overridden since we need to produce error tokens for unrecognized input,
//by default such content is only skipped and the resulting token sequence
//contains "holes".
//
//this way of solving the proble seems to be the official one:
//http://www.antlr.org/wiki/pages/viewpage.action?pageId=5341230
public Token nextToken() {
while (true) {
state.token = null;
state.channel = Token.DEFAULT_CHANNEL;
state.tokenStartCharIndex = input.index();
state.tokenStartCharPositionInLine = input.getCharPositionInLine();
state.tokenStartLine = input.getLine();
state.text = null;
if (input.LA(1) == CharStream.EOF) {
Token eof = new CommonToken(input, Token.EOF,
Token.DEFAULT_CHANNEL,
input.index(), input.index());
eof.setLine(getLine());
eof.setCharPositionInLine(getCharPositionInLine());
return eof;
}
try {
mTokens();
if (state.token == null) {
emit();
} else if (state.token == Token.SKIP_TOKEN) {
continue;
}
return state.token;
} catch (RecognitionException re) {
reportError(re);
if (re instanceof NoViableAltException) {
recover(re);
}
// create token that holds mismatched char
Token t = new CommonToken(input, Token.INVALID_TOKEN_TYPE,
Token.DEFAULT_CHANNEL,
state.tokenStartCharIndex,
getCharIndex() - 1);
t.setLine(state.tokenStartLine);
t.setCharPositionInLine(state.tokenStartCharPositionInLine);
emit(t);
return state.token;
}
}
}
@Override
@NbBundle.Messages({
"# {0} - the unexpected character",
"MSG_Error_Unexpected_Char=Unexpected character(s) {0} found"
})
public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
StringBuilder b = new StringBuilder();
b.append(getErrorHeader(e));
b.append(' ');
if (e instanceof NoViableAltException) {
//lexing error - unexpected character in the char stream
char unexpectedChar = (char) input.LA(1);
b.append(MSG_Error_Unexpected_Char(unexpectedChar));
ProblemDescription pp = new ProblemDescription(e.input.index(), e.input.index() + 1, b.toString(), ProblemDescription.Keys.LEXING.name(), Type.ERROR);
problems.add(pp);
} else {
b.append(getErrorHeader(e));
b.append(getErrorMessage(e, tokenNames));
}
}
public List<ProblemDescription> getProblems() {
return problems;
}
@Override
protected boolean isLessSource() {
return isLessSource;
}
@Override
protected boolean isScssSource() {
return isScssSource;
}
}