Merge remote-tracking branch 'origin/master'

This commit is contained in:
Alexey Kudravtsev
2013-10-22 15:52:54 +04:00
11 changed files with 1971 additions and 1707 deletions
@@ -0,0 +1,42 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed 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.jetbrains.plugins.groovy.highlighter;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
/**
* Created by Max Medvedev on 10/22/13
*/
public class GroovyDollarSlashyStringLexer extends GroovyStringLexerBase {
public GroovyDollarSlashyStringLexer() {
super(GroovyTokenTypes.mDOLLAR_SLASH_REGEX_CONTENT);
}
@Override
protected boolean checkForSimpleValidEscape(int start) {
return charAt(start) == '$' && start + 1 < getBufferEnd() && (charAt(start + 1) == '$' || charAt(start + 1) == '/');
}
@Override
protected boolean checkForInvalidSimpleEscape(int start) {
return false;
}
@Override
protected boolean checkForHexCodeStart(int start) {
return false;
}
}
@@ -15,107 +15,29 @@
*/
package org.jetbrains.plugins.groovy.highlighter;
import com.intellij.diagnostic.LogMessageEx;
import com.intellij.lexer.LexerBase;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.StringEscapesTokenTypes;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
/**
* @author Max Medvedev
*/
public class GroovySlashyStringLexer extends LexerBase {
private static final Logger LOG = Logger.getInstance(GroovySlashyStringLexer.class);
private CharSequence myBuffer;
private int myStart;
private int myBufferEnd;
private IElementType myTokenType;
private int myEnd;
public class GroovySlashyStringLexer extends GroovyStringLexerBase {
public GroovySlashyStringLexer() {
super(GroovyTokenTypes.mREGEX_CONTENT);
}
@Override
public void start(@NotNull CharSequence buffer, int startOffset, int endOffset, int initialState) {
if (buffer.length()<endOffset) {
LogMessageEx.error(LOG, "buffer Length: " + buffer.length() + ", endOffset: " + endOffset, buffer.toString());
}
myBuffer = buffer;
myEnd = startOffset;
myBufferEnd = endOffset;
myTokenType = locateToken();
}
@Nullable
private IElementType locateToken() {
if (myEnd >= myBufferEnd) return null;
myStart = myEnd;
if (checkForSlashEscape(myStart)) {
myEnd = myStart + 2;
return StringEscapesTokenTypes.VALID_STRING_ESCAPE_TOKEN;
}
else if (checkForHexCodeStart(myStart)) {
for (myEnd = myStart + 2; myEnd < myStart + 6; myEnd++) {
if (myEnd >= myBufferEnd || !StringUtil.isHexDigit(myBuffer.charAt(myEnd))) {
return StringEscapesTokenTypes.INVALID_UNICODE_ESCAPE_TOKEN;
}
}
return StringEscapesTokenTypes.VALID_STRING_ESCAPE_TOKEN;
}
while (myEnd < myBufferEnd && !checkForSlashEscape(myEnd) && !checkForHexCodeStart(myEnd)) myEnd++;
return GroovyTokenTypes.mREGEX_CONTENT;
}
private boolean checkForSlashEscape(int start) {
return myBuffer.charAt(start) == '\\' && start + 1 < myBufferEnd && myBuffer.charAt(start + 1) == '/';
}
private boolean checkForHexCodeStart(int start) {
return myBuffer.charAt(start) == '\\' && start + 1 < myBufferEnd && myBuffer.charAt(start + 1) == 'u';
protected boolean checkForSimpleValidEscape(int start) {
return charAt(start) == '\\' && start + 1 < getBufferEnd() && charAt(start + 1) == '/';
}
@Override
public int getState() {
return 0;
protected boolean checkForInvalidSimpleEscape(int start) {
return false;
}
@Override
public IElementType getTokenType() {
return myTokenType;
}
@Override
public int getTokenStart() {
return myStart;
}
@Override
public int getTokenEnd() {
return myEnd;
}
@Override
public void advance() {
myTokenType = locateToken();
}
@NotNull
@Override
public CharSequence getBufferSequence() {
return myBuffer;
}
@Override
public int getBufferEnd() {
return myBufferEnd;
protected boolean checkForHexCodeStart(int start) {
return charAt(start) == '\\' && start + 1 < getBufferEnd() && charAt(start + 1) == 'u';
}
}
@@ -0,0 +1,129 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed 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.jetbrains.plugins.groovy.highlighter;
import com.intellij.diagnostic.LogMessageEx;
import com.intellij.lexer.LexerBase;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.StringEscapesTokenTypes;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Created by Max Medvedev on 10/22/13
*/
public abstract class GroovyStringLexerBase extends LexerBase {
private static final Logger LOG = Logger.getInstance(GroovyStringLexerBase.class);
private final IElementType myContentElementType;
private CharSequence myBuffer;
private int myBufferEnd;
private int myStart;
private int myEnd;
private IElementType myTokenType;
public GroovyStringLexerBase(IElementType contentElementType) {
myContentElementType = contentElementType;
}
@Override
public void start(@NotNull CharSequence buffer, int startOffset, int endOffset, int initialState) {
if (buffer.length() < endOffset) {
LogMessageEx.error(LOG, "buffer Length: " + buffer.length() + ", endOffset: " + endOffset, buffer.toString());
}
myBuffer = buffer;
myEnd = startOffset;
myBufferEnd = endOffset;
myTokenType = locateToken();
}
@Nullable
private IElementType locateToken() {
if (myEnd >= myBufferEnd) return null;
myStart = myEnd;
if (checkForSimpleValidEscape(myStart)) {
myEnd = myStart + 2;
return StringEscapesTokenTypes.VALID_STRING_ESCAPE_TOKEN;
}
else if (checkForHexCodeStart(myStart)) {
for (myEnd = myStart + 2; myEnd < myStart + 6; myEnd++) {
if (myEnd >= myBufferEnd || !StringUtil.isHexDigit(myBuffer.charAt(myEnd))) {
return StringEscapesTokenTypes.INVALID_UNICODE_ESCAPE_TOKEN;
}
}
return StringEscapesTokenTypes.VALID_STRING_ESCAPE_TOKEN;
}
else if (checkForInvalidSimpleEscape(myStart)) {
myEnd = myStart + 2;
return StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN;
}
while (myEnd < myBufferEnd && !checkForSimpleValidEscape(myEnd) && !checkForHexCodeStart(myEnd)) myEnd++;
return myContentElementType;
}
protected abstract boolean checkForSimpleValidEscape(int start);
protected abstract boolean checkForInvalidSimpleEscape(int start);
protected abstract boolean checkForHexCodeStart(int start);
@Override
public int getState() {
return 0;
}
@Override
public IElementType getTokenType() {
return myTokenType;
}
@Override
public int getTokenStart() {
return myStart;
}
@Override
public int getTokenEnd() {
return myEnd;
}
@Override
public void advance() {
myTokenType = locateToken();
}
@NotNull
@Override
public CharSequence getBufferSequence() {
return myBuffer;
}
@Override
public int getBufferEnd() {
return myBufferEnd;
}
protected char charAt(int i) {
return myBuffer.charAt(i);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -131,8 +131,8 @@ public class GroovySyntaxHighlighter extends SyntaxHighlighterBase implements Gr
new IElementType[]{GroovyTokenTypes.mGSTRING_LITERAL}, IElementType.EMPTY_ARRAY);
registerSelfStoppingLayer(new StringLiteralLexer(StringLiteralLexer.NO_QUOTE_CHAR, GroovyTokenTypes.mGSTRING_CONTENT, true, "$"),
new IElementType[]{GroovyTokenTypes.mGSTRING_CONTENT}, IElementType.EMPTY_ARRAY);
registerSelfStoppingLayer(new GroovySlashyStringLexer(), new IElementType[]{GroovyTokenTypes.mREGEX_CONTENT},
IElementType.EMPTY_ARRAY);
registerSelfStoppingLayer(new GroovySlashyStringLexer(), new IElementType[]{GroovyTokenTypes.mREGEX_CONTENT}, IElementType.EMPTY_ARRAY);
registerSelfStoppingLayer(new GroovyDollarSlashyStringLexer(), new IElementType[]{GroovyTokenTypes.mDOLLAR_SLASH_REGEX_CONTENT}, IElementType.EMPTY_ARRAY);
}
}
File diff suppressed because it is too large Load Diff
@@ -19,11 +19,11 @@ import com.intellij.lexer.FlexLexer;
import com.intellij.psi.TokenType;
import com.intellij.psi.tree.IElementType;
import java.util.*;
import java.lang.reflect.Field;
import org.jetbrains.annotations.NotNull;
%%
%{@SuppressWarnings({"UnnecessaryFullyQualifiedName", "FieldCanBeLocal", "UnusedDeclaration", "UnusedAssignment", "AccessStaticViaInstance",
"AssignmentToStaticFieldFromInstanceMethod", "MethodMayBeStatic", "CStyleArrayDeclaration", "UnnecessarySemicolon"}) %}
%class _GroovyLexer
%implements FlexLexer, GroovyTokenTypes, TokenType
%unicode
@@ -144,7 +144,7 @@ mREGEX_ESC = \\ "/"
mREGEX_CONTENT = ({mREGEX_ESC} | [^"/""$"])+
mDOLLAR_SLASH_REGEX_CONTENT = ([^\/\$] | \/[^\/\$] )+
mDOLLAR_SLASH_REGEX_CONTENT = ([^\/\$] | \$\$ | \$\/ | \/[^\/\$] )+
////////////////////////////////////////////////////////////////////////////
@@ -8,12 +8,11 @@
private static final int ZZ_UNKNOWN_ERROR = 0;
private static final int ZZ_NO_MATCH = 1;
private static final int ZZ_PUSHBACK_2BIG = 2;
private static final char[] EMPTY_BUFFER = new char[0];
private static final int YYEOF = -1;
private static java.io.Reader zzReader = null; // Fake
/* error messages for the codes above */
private static final String ZZ_ERROR_MSG[] = {
private static final String[] ZZ_ERROR_MSG = {
"Unkown internal scanner error",
"Error: could not match input",
"Error: pushback value was too large"
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -89,7 +89,7 @@ public class GrSyntheticTypeElement extends LightElement implements PsiTypeEleme
@Override
public PsiElement replace(@NotNull PsiElement newElement) throws IncorrectOperationException {
if (newElement instanceof PsiTypeElement) {
GrTypeElement groovyTypeElement = GroovyPsiElementFactory.getInstance(getProject()).createTypeElement(newElement.getText(), newElement);
GrTypeElement groovyTypeElement = GroovyPsiElementFactory.getInstance(getProject()).createTypeElement(((PsiTypeElement)newElement).getType());
return myElement.replace(groovyTypeElement);
}
else {
@@ -98,6 +98,9 @@ public class GroovyOverrideImplementUtil {
for (PsiAnnotation annotation : original.getModifierList().getAnnotations()) {
final GrModifierList modifierList = parameter.getModifierList();
String qname = annotation.getQualifiedName();
if (annotation instanceof GrAnnotation) {
modifierList.add(annotation);
}
@@ -356,6 +356,8 @@ public class ExpressionsParsingTest extends GroovyParsingTestCase {
public void testregex$dollarSlashyTriple() throws Throwable { doTest(); }
public void testregex$dollarSlashyUltimate() { doTest() }
public void testrelational$eq1() throws Throwable { doTest(); }
public void testrelational$inst0() throws Throwable { doTest(); }
@@ -0,0 +1,147 @@
def name = "Guillaume"
def date = "April, 1st"
def dollarSlashy = $/
Hello $name,
today we're ${date}.
$ dollar sign
$$ escaped dollar sign
\ backslash
/ forward slash
$/ escaped forward slash
$/$ escaped dollar slashy string delimiter
/$
assert [
'Guillaume',
'April, 1st',
'$ dollar sign',
'$ escaped dollar sign',
'\\ backslash',
'/ forward slash',
'$/ escaped forward slash',
'/$ escaped dollar slashy string delimiter'
].each { dollarSlashy.contains(it) }
-----
Groovy script
Variable definitions
Modifiers
PsiElement(def)('def')
PsiWhiteSpace(' ')
Variable
PsiElement(identifier)('name')
PsiWhiteSpace(' ')
PsiElement(=)('=')
PsiWhiteSpace(' ')
Literal
PsiElement(Gstring)('"Guillaume"')
PsiElement(new line)('\n')
Variable definitions
Modifiers
PsiElement(def)('def')
PsiWhiteSpace(' ')
Variable
PsiElement(identifier)('date')
PsiWhiteSpace(' ')
PsiElement(=)('=')
PsiWhiteSpace(' ')
Literal
PsiElement(Gstring)('"April, 1st"')
PsiElement(new line)('\n\n')
Variable definitions
Modifiers
PsiElement(def)('def')
PsiWhiteSpace(' ')
Variable
PsiElement(identifier)('dollarSlashy')
PsiWhiteSpace(' ')
PsiElement(=)('=')
PsiWhiteSpace(' ')
Compound regular expression
PsiElement($/ regex begin)('$/')
GrStringContentImpl(GString content element)
PsiElement($/ regex content)('\n Hello ')
GString injection
PsiElement($)('$')
Reference expression
PsiElement(identifier)('name')
GrStringContentImpl(GString content element)
PsiElement($/ regex content)(',\n today we're ')
GString injection
PsiElement($)('$')
Closable block
PsiElement({)('{')
Parameter list
<empty list>
Reference expression
PsiElement(identifier)('date')
PsiElement(})('}')
GrStringContentImpl(GString content element)
PsiElement($/ regex content)('.\n\n $ dollar sign\n $$ escaped dollar sign\n \ backslash\n / forward slash\n $/ escaped forward slash\n $/$ escaped dollar slashy string delimiter\n')
PsiElement($/ regex end)('/$')
PsiElement(new line)('\n\n')
ASSERT statement
PsiElement(assert)('assert')
PsiWhiteSpace(' ')
Method call
Reference expression
Generalized list
PsiElement([)('[')
PsiWhiteSpace('\n ')
Literal
PsiElement(string)(''Guillaume'')
PsiElement(,)(',')
PsiWhiteSpace('\n ')
Literal
PsiElement(string)(''April, 1st'')
PsiElement(,)(',')
PsiWhiteSpace('\n ')
Literal
PsiElement(string)(''$ dollar sign'')
PsiElement(,)(',')
PsiWhiteSpace('\n ')
Literal
PsiElement(string)(''$ escaped dollar sign'')
PsiElement(,)(',')
PsiWhiteSpace('\n ')
Literal
PsiElement(string)(''\\ backslash'')
PsiElement(,)(',')
PsiWhiteSpace('\n ')
Literal
PsiElement(string)(''/ forward slash'')
PsiElement(,)(',')
PsiWhiteSpace('\n')
Literal
PsiElement(string)(''$/ escaped forward slash'')
PsiElement(,)(',')
PsiWhiteSpace('\n')
Literal
PsiElement(string)(''/$ escaped dollar slashy string delimiter'')
PsiWhiteSpace('\n\n')
PsiElement(])(']')
PsiElement(.)('.')
PsiElement(identifier)('each')
PsiWhiteSpace(' ')
Arguments
<empty list>
Closable block
PsiElement({)('{')
PsiWhiteSpace(' ')
Parameter list
<empty list>
Method call
Reference expression
Reference expression
PsiElement(identifier)('dollarSlashy')
PsiElement(.)('.')
PsiElement(identifier)('contains')
Arguments
PsiElement(()('(')
Reference expression
PsiElement(identifier)('it')
PsiElement())(')')
PsiWhiteSpace(' ')
PsiElement(})('}')