Author: akazakov
Date: 2007-10-11 12:53:32 -0400 (Thu, 11 Oct 2007)
New Revision: 4122
Added:
trunk/seam/plugins/org.jboss.tools.seam.core/src/org/jboss/tools/seam/internal/core/el/ELToken.java
trunk/seam/plugins/org.jboss.tools.seam.core/src/org/jboss/tools/seam/internal/core/el/SeamELTokenizer.java
Modified:
trunk/seam/plugins/org.jboss.tools.seam.core/src/org/jboss/tools/seam/internal/core/el/SeamELCompletionEngine.java
trunk/seam/plugins/org.jboss.tools.seam.core/src/org/jboss/tools/seam/internal/core/validation/SeamELValidator.java
trunk/seam/plugins/org.jboss.tools.seam.core/src/org/jboss/tools/seam/internal/core/validation/messages.properties
trunk/seam/plugins/org.jboss.tools.seam.ui/src/org/jboss/tools/seam/ui/preferences/SeamPreferencesMessages.properties
Log:
http://jira.jboss.com/jira/browse/JBIDE-1039
Added:
trunk/seam/plugins/org.jboss.tools.seam.core/src/org/jboss/tools/seam/internal/core/el/ELToken.java
===================================================================
---
trunk/seam/plugins/org.jboss.tools.seam.core/src/org/jboss/tools/seam/internal/core/el/ELToken.java
(rev 0)
+++
trunk/seam/plugins/org.jboss.tools.seam.core/src/org/jboss/tools/seam/internal/core/el/ELToken.java 2007-10-11
16:53:32 UTC (rev 4122)
@@ -0,0 +1,116 @@
+ /*******************************************************************************
+ * Copyright (c) 2007 Red Hat, Inc.
+ * Distributed under license by Red Hat, Inc. All rights reserved.
+ * This program is made available under the terms of the
+ * Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at
http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ ******************************************************************************/
+package org.jboss.tools.seam.internal.core.el;
+
+import org.eclipse.jface.text.rules.IToken;
+
+/**
+ * Token for the EL expression parts
+ * @author Alexey Kazakov
+ */
+public class ELToken implements IToken {
+ public static final ELToken EOF = new ELToken(-1, -1, null, -1);
+ public static final int EL_OPERAND_TOKEN = 1;
+ public static final int EL_OPERATOR_TOKEN = 2;
+ public static final int EL_RESERVED_WORD_TOKEN = 3;
+ public static final int EL_SEPARATOR_TOKEN = 4;
+
+ private int start;
+ private int length;
+ private CharSequence chars;
+ private int type;
+
+ /**
+ * Constructs the ELToken object
+ *
+ * @param start
+ * @param length
+ * @param chars
+ * @param type
+ */
+ public ELToken(int start, int length, CharSequence chars, int type) {
+ this.start = start;
+ this.length = length;
+ this.chars = chars;
+ this.type = type;
+ }
+
+ /**
+ * Returns string representation for the token
+ */
+ public String toString() {
+ return "ELToken(" + start + ", " + length + ", " + type +
") [" + (chars == null ? "<Empty>" : chars.toString()) +
"]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
//$NON-NLS-6$
+ }
+
+ /*
+ * @see org.eclipse.jface.text.rules.IToken#getData()
+ */
+ public Object getData() {
+// return (chars == null ? null : chars.subSequence(start, start+length).toString());
+ return getText();
+ }
+
+ /**
+ * @return offset of token
+ */
+ public int getStart() {
+ return start;
+ }
+
+ /**
+ * @return length of token
+ */
+ public int getLength() {
+ return length;
+ }
+
+ /*
+ * @see org.eclipse.jface.text.rules.IToken#isEOF()
+ */
+ public boolean isEOF() {
+ return (start == -1 && length == -1 && chars == null);
+ }
+
+ /*
+ * @see org.eclipse.jface.text.rules.IToken#isOther()
+ */
+ public boolean isOther() {
+ return false;
+ }
+
+ /*
+ * @see org.eclipse.jface.text.rules.IToken#isUndefined()
+ */
+ public boolean isUndefined() {
+ return false;
+ }
+
+ /*
+ * @see org.eclipse.jface.text.rules.IToken#isWhitespace()
+ */
+ public boolean isWhitespace() {
+ return false;
+ }
+
+ /*
+ * Returns the token type
+ */
+ public int getType(){
+ return type;
+ }
+
+ /*
+ * Returns the token text
+ */
+ public String getText() {
+ return chars.toString();
+ }
+}
\ No newline at end of file
Modified:
trunk/seam/plugins/org.jboss.tools.seam.core/src/org/jboss/tools/seam/internal/core/el/SeamELCompletionEngine.java
===================================================================
---
trunk/seam/plugins/org.jboss.tools.seam.core/src/org/jboss/tools/seam/internal/core/el/SeamELCompletionEngine.java 2007-10-11
16:02:27 UTC (rev 4121)
+++
trunk/seam/plugins/org.jboss.tools.seam.core/src/org/jboss/tools/seam/internal/core/el/SeamELCompletionEngine.java 2007-10-11
16:53:32 UTC (rev 4122)
@@ -95,18 +95,18 @@
int position, boolean returnEqualedVariablesOnly, Set<ISeamContextVariable>
usedVariables, Map<String, IMethod> unpairedGettersOrSetters) throws
BadLocationException, StringIndexOutOfBoundsException {
List<String> res= new ArrayList<String>();
- SeamELTokenizer tokenizer = new SeamELTokenizer(documentContent, position +
prefix.length());
- List<ELToken> tokens = tokenizer.getTokens();
+ SeamELOperandTokenizer tokenizer = new SeamELOperandTokenizer(documentContent, position
+ prefix.length());
+ List<ELOperandToken> tokens = tokenizer.getTokens();
- List<ELToken> resolvedExpressionPart = new ArrayList<ELToken>();
+ List<ELOperandToken> resolvedExpressionPart = new
ArrayList<ELOperandToken>();
List<ISeamContextVariable> resolvedVariables = new
ArrayList<ISeamContextVariable>();
ScopeType scope = getScope(project, file);
- List<List<ELToken>> variations = getPossibleVarsFromPrefix(tokens);
+ List<List<ELOperandToken>> variations = getPossibleVarsFromPrefix(tokens);
if (variations.isEmpty()) {
resolvedVariables = resolveVariables(project, scope, tokens, tokens,
returnEqualedVariablesOnly);
} else {
- for (List<ELToken> variation : variations) {
+ for (List<ELOperandToken> variation : variations) {
List<ISeamContextVariable>resolvedVars = new
ArrayList<ISeamContextVariable>();
resolvedVars = resolveVariables(project, scope, variation, tokens,
returnEqualedVariablesOnly);
if (resolvedVars != null && !resolvedVars.isEmpty()) {
@@ -150,14 +150,14 @@
tokens != null && i < tokens.size() &&
members != null && members.size() > 0;
i++) {
- ELToken token = tokens.get(i);
+ ELOperandToken token = tokens.get(i);
if (i < tokens.size() - 1) { // inside expression
- if (token.getType() == ELToken.EL_SEPARATOR_TOKEN)
+ if (token.getType() == ELOperandToken.EL_SEPARATOR_TOKEN)
// proceed with next token
continue;
- if (token.getType() == ELToken.EL_NAME_TOKEN) {
+ if (token.getType() == ELOperandToken.EL_NAME_TOKEN) {
// Find properties for the token
String name = token.getText();
Set<IMember> newMembers = new HashSet<IMember>();
@@ -181,7 +181,7 @@
}
members = newMembers;
}
- if (token.getType() == ELToken.EL_METHOD_TOKEN) {
+ if (token.getType() == ELOperandToken.EL_METHOD_TOKEN) {
// Find methods for the token
String name = token.getText();
if (name.indexOf('(') != -1) {
@@ -205,7 +205,7 @@
}
} else { // Last segment
Set<String> proposals = new
TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
- if (token.getType() == ELToken.EL_SEPARATOR_TOKEN) {
+ if (token.getType() == ELOperandToken.EL_SEPARATOR_TOKEN) {
// return all the methods + properties
for (IMember mbr : members) {
try {
@@ -216,8 +216,8 @@
SeamCorePlugin.getPluginLog().logError(ex);
}
}
- } else if (token.getType() == ELToken.EL_NAME_TOKEN ||
- token.getType() == ELToken.EL_METHOD_TOKEN) {
+ } else if (token.getType() == ELOperandToken.EL_NAME_TOKEN ||
+ token.getType() == ELOperandToken.EL_METHOD_TOKEN) {
// return filtered methods + properties
Set<String> proposalsToFilter = new
TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
for (IMember mbr : members) {
@@ -268,14 +268,14 @@
return res;
}
- private String computeVariableName(List<ELToken> tokens){
+ private String computeVariableName(List<ELOperandToken> tokens){
if (tokens == null)
- tokens = new ArrayList<ELToken>();
+ tokens = new ArrayList<ELOperandToken>();
StringBuffer sb = new StringBuffer();
- for (ELToken token : tokens) {
- if (token.getType() == ELToken.EL_NAME_TOKEN ||
- token.getType() == ELToken.EL_METHOD_TOKEN ||
- token.getType() == ELToken.EL_SEPARATOR_TOKEN) {
+ for (ELOperandToken token : tokens) {
+ if (token.getType() == ELOperandToken.EL_NAME_TOKEN ||
+ token.getType() == ELOperandToken.EL_METHOD_TOKEN ||
+ token.getType() == ELOperandToken.EL_SEPARATOR_TOKEN) {
sb.append(token.getText());
}
}
@@ -289,7 +289,7 @@
* @param second
* @return boolean true if two expressions are equal
*/
- private boolean areEqualExpressions(List<ELToken>first, List<ELToken>second)
{
+ private boolean areEqualExpressions(List<ELOperandToken>first,
List<ELOperandToken>second) {
if (first == null || second == null)
return (first == second);
@@ -334,7 +334,7 @@
* @param tokens
* @return
*/
- private List<ISeamContextVariable> resolveVariables(ISeamProject project,
ScopeType scope, List<ELToken>part, List<ELToken> tokens, boolean
onlyEqualNames) {
+ private List<ISeamContextVariable> resolveVariables(ISeamProject project,
ScopeType scope, List<ELOperandToken>part, List<ELOperandToken> tokens,
boolean onlyEqualNames) {
List<ISeamContextVariable>resolvedVars = new
ArrayList<ISeamContextVariable>();
String varName = computeVariableName(part);
if (varName != null) {
@@ -365,12 +365,12 @@
* @param prefix
* @return
*/
- private List<List<ELToken>>
getPossibleVarsFromPrefix(List<ELToken>prefix) {
- ArrayList<List<ELToken>> result = new
ArrayList<List<ELToken>>();
+ private List<List<ELOperandToken>>
getPossibleVarsFromPrefix(List<ELOperandToken>prefix) {
+ ArrayList<List<ELOperandToken>> result = new
ArrayList<List<ELOperandToken>>();
for (int i = 0; prefix != null && i < prefix.size(); i++) {
- ELToken lastToken = prefix.get(i);
- if (lastToken.getType() != ELToken.EL_SEPARATOR_TOKEN) {
- ArrayList<ELToken> prefixPart = new ArrayList<ELToken>();
+ ELOperandToken lastToken = prefix.get(i);
+ if (lastToken.getType() != ELOperandToken.EL_SEPARATOR_TOKEN) {
+ ArrayList<ELOperandToken> prefixPart = new ArrayList<ELOperandToken>();
for (int j = 0; j <= i; j++) {
prefixPart.add(prefix.get(j));
}
@@ -403,50 +403,47 @@
present.clear();
return unique;
}
-
+
/**
* EL string parser.
* Creates list of tokens for the name, method and separator parts
- *
+ *
* @author Jeremy
*/
- public static class SeamELTokenizer {
+ public static class SeamELOperandTokenizer {
static final int STATE_INITIAL = 0;
static final int STATE_VAR = 1;
static final int STATE_METHOD = 2;
static final int STATE_SEPARATOR = 3;
-
-// IDocument fDocument;
+
String documentContent;
- List<ELToken> fTokens;
+ List<ELOperandToken> fTokens;
int index;
/**
- * Constructs SeamELTokenizer object
- *
- * @param document
+ * Constructs SeamELTokenizer object.
+ * Parse expression from offset to first operator or space.
+ * Tokenizer parses document from offset to beginning.
+ * For example: documentContetn is '<tag
attr="#{var1.pr!=var2.pr}"/>'
+ * offset = 29 ("...var2.pr|}")
+ * then tokens are {"pr",".","var2"}
+ * @param documentContent
* @param offset
*/
- public SeamELTokenizer(IDocument document, int offset) {
- if(document!=null) {
- this.documentContent = document.get();
- }
+ public SeamELOperandTokenizer(String documentContent, int offset) {
+ this.documentContent = documentContent;
index = (documentContent == null || documentContent.length() < offset? -1 :
offset);
- fTokens = new ArrayList<ELToken>();
+ fTokens = new ArrayList<ELOperandToken>();
parseBackward();
}
/**
- * Constructs SeamELTokenizer object
- *
+ * Constructs SeamELTokenizer object.
* @param document
* @param offset
*/
- public SeamELTokenizer(String documentContent, int offset) {
- this.documentContent = documentContent;
- index = (documentContent == null || documentContent.length() < offset? -1 :
offset);
- fTokens = new ArrayList<ELToken>();
- parseBackward();
+ public SeamELOperandTokenizer(IDocument document, int offset) {
+ this(document.get(), offset);
}
/**
@@ -454,27 +451,27 @@
*
* @return
*/
- public List<ELToken> getTokens() {
+ public List<ELOperandToken> getTokens() {
return fTokens;
}
-
+
/*
* Performs backward parsing of document text for expression
*/
private void parseBackward() {
- ELToken token;
+ ELOperandToken token;
fState = STATE_INITIAL;
- while ((token = getNextToken()) != ELToken.EOF) {
-
- if (token.type == ELToken.EL_NAME_TOKEN ||
- token.type == ELToken.EL_METHOD_TOKEN ||
- token.type == ELToken.EL_SEPARATOR_TOKEN) {
-
+ while ((token = getNextToken()) != ELOperandToken.EOF) {
+
+ if (token.type == ELOperandToken.EL_NAME_TOKEN ||
+ token.type == ELOperandToken.EL_METHOD_TOKEN ||
+ token.type == ELOperandToken.EL_SEPARATOR_TOKEN) {
+
fTokens.add(0, token);
}
}
}
-
+
int fState;
int fEndOfToken;
@@ -483,13 +480,13 @@
*
* @return
*/
- private ELToken getNextToken() {
+ private ELOperandToken getNextToken() {
switch (fState) {
case STATE_INITIAL: // Just started
{
int ch = readCharBackward();
if (ch == -1) {
- return ELToken.EOF;
+ return ELOperandToken.EOF;
}
if (Character.isJavaIdentifierPart((char)ch)) {
releaseChar();
@@ -504,39 +501,39 @@
return readMethodToken();
}
releaseChar();
- return ELToken.EOF;
+ return ELOperandToken.EOF;
}
case STATE_VAR: // Variable name is read - expecting a separator
{
int ch = readCharBackward();
if (ch == -1) {
- return ELToken.EOF;
+ return ELOperandToken.EOF;
}
if (ch == '.') {
releaseChar();
return readSeparatorToken();
}
releaseChar();
- return ELToken.EOF;
+ return ELOperandToken.EOF;
}
case STATE_METHOD: // Method name and parameters are read - expecting a separator
{
int ch = readCharBackward();
if (ch == -1) {
- return ELToken.EOF;
+ return ELOperandToken.EOF;
}
if (ch == '.') {
releaseChar();
return readSeparatorToken();
}
releaseChar();
- return ELToken.EOF;
+ return ELOperandToken.EOF;
}
case STATE_SEPARATOR: // Separator is read - expecting a var or method
{
int ch = readCharBackward();
if (ch == -1) {
- return ELToken.EOF;
+ return ELOperandToken.EOF;
}
if (Character.isJavaIdentifierPart((char)ch)) {
releaseChar();
@@ -547,32 +544,32 @@
return readMethodToken();
}
releaseChar();
- return ELToken.EOF;
+ return ELOperandToken.EOF;
}
}
- return ELToken.EOF;
+ return ELOperandToken.EOF;
}
/* Reads and returns the method token from the expression
*
* @return
*/
- ELToken readMethodToken() {
+ ELOperandToken readMethodToken() {
fState = STATE_METHOD;
int endOfToken = index;
// read the method parameters
if (!skipMethodParameters())
- return ELToken.EOF;
+ return ELOperandToken.EOF;
// skip spaces between the method's name and it's parameters
if (!skipSpaceChars())
- return ELToken.EOF;
+ return ELOperandToken.EOF;
// read the method name
if (!skipMethodName())
- return ELToken.EOF;
+ return ELOperandToken.EOF;
- return (endOfToken - index > 0 ? new ELToken(index, endOfToken - index,
getCharSequence(index, endOfToken - index), ELToken.EL_METHOD_TOKEN) : ELToken.EOF);
+ return (endOfToken - index > 0 ? new ELOperandToken(index, endOfToken - index,
getCharSequence(index, endOfToken - index), ELOperandToken.EL_METHOD_TOKEN) :
ELOperandToken.EOF);
}
/*
@@ -686,30 +683,30 @@
*
* @return
*/
- ELToken readSeparatorToken() {
+ ELOperandToken readSeparatorToken() {
fState = STATE_SEPARATOR;
int ch = readCharBackward();
- return (ch == '.' ? new ELToken(index, 1, getCharSequence(index, 1),
ELToken.EL_SEPARATOR_TOKEN) :
- ELToken.EOF);
+ return (ch == '.' ? new ELOperandToken(index, 1, getCharSequence(index, 1),
ELOperandToken.EL_SEPARATOR_TOKEN) :
+ ELOperandToken.EOF);
}
/* Reads and returns the variable token from the expression
*
* @return
*/
- ELToken readVarToken() {
+ ELOperandToken readVarToken() {
fState = STATE_VAR;
int endOfToken = index;
int ch;
while((ch = readCharBackward()) != -1) {
if (!Character.isJavaIdentifierPart(ch)) {
releaseChar();
- return (endOfToken - index > 0 ? new ELToken(index, endOfToken - index,
getCharSequence(index, endOfToken - index), ELToken.EL_NAME_TOKEN) : ELToken.EOF);
+ return (endOfToken - index > 0 ? new ELOperandToken(index, endOfToken - index,
getCharSequence(index, endOfToken - index), ELOperandToken.EL_NAME_TOKEN) :
ELOperandToken.EOF);
}
}
releaseChar();
- return (endOfToken - index > 0 ? new ELToken(index, endOfToken - index,
getCharSequence(index, endOfToken - index), ELToken.EL_NAME_TOKEN) : ELToken.EOF);
+ return (endOfToken - index > 0 ? new ELOperandToken(index, endOfToken - index,
getCharSequence(index, endOfToken - index), ELOperandToken.EL_NAME_TOKEN) :
ELOperandToken.EOF);
}
/* Reads the next character in the document
@@ -759,33 +756,32 @@
* @param viewer
* @param offset
* @return
- * @throws BadLocationException
+ * @throws StringIndexOutOfBoundsException
*/
public static String getPrefix(String documentContent, int offset) throws
StringIndexOutOfBoundsException {
if (documentContent == null || offset > documentContent.length())
return null;
- SeamELTokenizer tokenizer = new SeamELTokenizer(documentContent, offset);
- List<ELToken> tokens = tokenizer.getTokens();
+ SeamELOperandTokenizer tokenizer = new SeamELOperandTokenizer(documentContent,
offset);
+ List<ELOperandToken> tokens = tokenizer.getTokens();
if (tokens == null || tokens.size() == 0)
return null;
return documentContent.substring(tokens.get(0).start, offset);
-// return documentContent.substring(tokens.get(0).start, tokens.get(0).start +
tokens.get(0).length);
}
-
+
public String getJavaElementExpression(String documentContent, int offset, IRegion
region) throws StringIndexOutOfBoundsException {
if (documentContent == null || offset > documentContent.length())
return null;
- SeamELTokenizer tokenizer = new SeamELTokenizer(documentContent, region.getOffset() +
region.getLength());
- List<ELToken> tokens = tokenizer.getTokens();
+ SeamELOperandTokenizer tokenizer = new SeamELOperandTokenizer(documentContent,
region.getOffset() + region.getLength());
+ List<ELOperandToken> tokens = tokenizer.getTokens();
if (tokens == null || tokens.size() == 0)
return null;
- List<List<ELToken>> vars = getPossibleVarsFromPrefix(tokens);
+ List<List<ELOperandToken>> vars = getPossibleVarsFromPrefix(tokens);
if (vars == null)
return null;
@@ -793,7 +789,7 @@
// Search from the shortest variation to the longest one
for (int i = vars.size() - 1; i >= 0; i--) {
- List<ELToken>var = vars.get(i);
+ List<ELOperandToken>var = vars.get(i);
String varText = computeVariableName(var);
if (varText != null && varText.startsWith(prefixPart)) {
return varText;
@@ -814,21 +810,21 @@
List<IJavaElement> res= new ArrayList<IJavaElement>();
- SeamELTokenizer tokenizer = new SeamELTokenizer(expression, expression.length());
- List<ELToken> tokens = tokenizer.getTokens();
+ SeamELOperandTokenizer tokenizer = new SeamELOperandTokenizer(expression,
expression.length());
+ List<ELOperandToken> tokens = tokenizer.getTokens();
- if (tokens == null || tokens.size() == 0 || tokens.get(tokens.size() - 1).getType() ==
ELToken.EL_SEPARATOR_TOKEN)
+ if (tokens == null || tokens.size() == 0 || tokens.get(tokens.size() - 1).getType() ==
ELOperandToken.EL_SEPARATOR_TOKEN)
return res;
- List<ELToken> resolvedExpressionPart = new ArrayList<ELToken>();
+ List<ELOperandToken> resolvedExpressionPart = new
ArrayList<ELOperandToken>();
List<ISeamContextVariable> resolvedVariables = new
ArrayList<ISeamContextVariable>();
ScopeType scope = getScope(project, file);
- List<List<ELToken>> variations = getPossibleVarsFromPrefix(tokens);
+ List<List<ELOperandToken>> variations = getPossibleVarsFromPrefix(tokens);
if (variations.isEmpty()) {
resolvedVariables = resolveVariables(project, scope, tokens, tokens, true);
} else {
- for (List<ELToken> variation : variations) {
+ for (List<ELOperandToken> variation : variations) {
List<ISeamContextVariable>resolvedVars = new
ArrayList<ISeamContextVariable>();
resolvedVars = resolveVariables(project, scope, variation, tokens, true);
if (resolvedVars != null && !resolvedVars.isEmpty()) {
@@ -844,13 +840,13 @@
if (areEqualExpressions(resolvedExpressionPart, tokens)) {
// First segment is the last one
for (ISeamContextVariable var : resolvedVariables) {
- String varName = var.getName();
-/* if(expression.length()<varName.length()) {
+/* String varName = var.getName();
+ if(expression.length()<varName.length()) {
res.add(varName.substring(prefixString.length()));
} else if(returnEqualedVariablesOnly) {
res.add(varName);
}
- */
+*/
IMember member = SeamExpressionResolver.getMemberByVariable(var, true);
if (member instanceof IJavaElement){
res.add((IJavaElement)member);
@@ -871,14 +867,14 @@
tokens != null && i < tokens.size() &&
members != null && members.size() > 0;
i++) {
- ELToken token = tokens.get(i);
+ ELOperandToken token = tokens.get(i);
if (i < tokens.size() - 1) { // inside expression
- if (token.getType() == ELToken.EL_SEPARATOR_TOKEN)
+ if (token.getType() == ELOperandToken.EL_SEPARATOR_TOKEN)
// proceed with next token
continue;
- if (token.getType() == ELToken.EL_NAME_TOKEN) {
+ if (token.getType() == ELOperandToken.EL_NAME_TOKEN) {
// Find properties for the token
String name = token.getText();
Set<IMember> newMembers = new HashSet<IMember>();
@@ -902,7 +898,7 @@
}
members = newMembers;
}
- if (token.getType() == ELToken.EL_METHOD_TOKEN) {
+ if (token.getType() == ELOperandToken.EL_METHOD_TOKEN) {
// Find methods for the token
String name = token.getText();
if (name.indexOf('(') != -1) {
@@ -926,8 +922,8 @@
}
} else { // Last segment
Set<IJavaElement> javaElements = new HashSet<IJavaElement>();
- if (token.getType() == ELToken.EL_NAME_TOKEN ||
- token.getType() == ELToken.EL_METHOD_TOKEN) {
+ if (token.getType() == ELOperandToken.EL_NAME_TOKEN ||
+ token.getType() == ELOperandToken.EL_METHOD_TOKEN) {
// return filtered methods + properties
Set<IJavaElement> javaElementsToFilter = new HashSet<IJavaElement>();
for (IMember mbr : members) {
@@ -982,12 +978,12 @@
}
/**
- * Token for the EX expression
- *
+ * Token for the EX expression operand parts
+ *
* @author Jeremy
*/
-class ELToken implements IToken {
- static final ELToken EOF = new ELToken(-1, -1, null, -1);
+class ELOperandToken implements IToken {
+ static final ELOperandToken EOF = new ELOperandToken(-1, -1, null, -1);
static final int EL_NAME_TOKEN = 1;
static final int EL_METHOD_TOKEN = 2;
static final int EL_SEPARATOR_TOKEN = 3;
@@ -1005,7 +1001,7 @@
* @param chars
* @param type
*/
- public ELToken(int start, int length, CharSequence chars, int type) {
+ public ELOperandToken(int start, int length, CharSequence chars, int type) {
this.start = start;
this.length = length;
this.chars = chars;
Added:
trunk/seam/plugins/org.jboss.tools.seam.core/src/org/jboss/tools/seam/internal/core/el/SeamELTokenizer.java
===================================================================
---
trunk/seam/plugins/org.jboss.tools.seam.core/src/org/jboss/tools/seam/internal/core/el/SeamELTokenizer.java
(rev 0)
+++
trunk/seam/plugins/org.jboss.tools.seam.core/src/org/jboss/tools/seam/internal/core/el/SeamELTokenizer.java 2007-10-11
16:53:32 UTC (rev 4122)
@@ -0,0 +1,264 @@
+ /*******************************************************************************
+ * Copyright (c) 2007 Red Hat, Inc.
+ * Distributed under license by Red Hat, Inc. All rights reserved.
+ * This program is made available under the terms of the
+ * Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at
http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ ******************************************************************************/
+package org.jboss.tools.seam.internal.core.el;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jboss.tools.seam.core.SeamCorePlugin;
+
+/**
+ * EL string parser.
+ * Creates list of tokens for the operands and operators
+ * @author Alexey Kazakov
+ */
+public class SeamELTokenizer {
+ private static final int STATE_INITIAL = 0;
+ private static final int STATE_OPERAND = 1;
+ private static final int STATE_OPERATOR = 2;
+ private static final int STATE_RESERVED_WORD = 3;
+ private static final int STATE_SEPARATOR = 4;
+
+ private String expression;
+ private List<ELToken> fTokens;
+ private int index;
+
+ private int fState;
+ private static final String OPERATOR_SYMBOLS =
"!=&(){}[]:+-*%?',|/%<>";
+ private static final String RESERVED_WORDS = " null empty div and or not mod eq ne
lt gt le ge true false instanceof ";
+
+ /**
+ * Constructs SeamELTokenizer object.
+ * Constructs SeamELTokenizer object
+ * Parse an expression.
+ * For example: expression is '#{var1.pr != var2.pr}'
+ * then tokens are {"var1.pr"," ", "!=",
" ", "var2",}
+ * @param expression
+ */
+ public SeamELTokenizer(String expression) {
+ this.expression = expression;
+ index = 0;
+ fTokens = new ArrayList<ELToken>();
+ parse();
+ }
+
+ /**
+ * Returns list of tokens for the expression parsed
+ *
+ * @return
+ */
+ public List<ELToken> getTokens() {
+ return fTokens;
+ }
+
+ /*
+ * Performs parsing of expression
+ */
+ private void parse() {
+ ELToken token;
+ fState = STATE_INITIAL;
+ while ((token = getNextToken()) != ELToken.EOF) {
+
+ if (token.getType() == ELToken.EL_OPERAND_TOKEN ||
+ token.getType() == ELToken.EL_OPERATOR_TOKEN ||
+ token.getType() == ELToken.EL_RESERVED_WORD_TOKEN ||
+ token.getType() == ELToken.EL_SEPARATOR_TOKEN) {
+
+ fTokens.add(token);
+ }
+ }
+ }
+
+ /*
+ * Calculates and returns next token for expression
+ *
+ * @return
+ */
+ private ELToken getNextToken() {
+ switch (fState) {
+ case STATE_INITIAL: { // Just started
+ int ch = readNextChar();
+ if (ch == -1) {
+ return ELToken.EOF;
+ }
+ releaseChar();
+ if (Character.isJavaIdentifierPart((char)ch)) {
+ return readOperandOrReservedWordToken();
+ }
+ if (OPERATOR_SYMBOLS.indexOf(ch)>-1) {
+ return readOperatorToken();
+ }
+ if (ch == ' ') {
+ return readSeparatorToken();
+ }
+ return ELToken.EOF;
+ }
+ case STATE_RESERVED_WORD: // Reserved word is read - expecting a separator or
operator
+ case STATE_OPERAND: { // Operand is read - expecting a separator or operator
+ int ch = readNextChar();
+ if (ch == -1) {
+ return ELToken.EOF;
+ }
+ releaseChar();
+ if (OPERATOR_SYMBOLS.indexOf(ch)>-1) {
+ return readOperatorToken();
+ }
+ if (ch == ' ') {
+ return readSeparatorToken();
+ }
+ return ELToken.EOF;
+ }
+ case STATE_OPERATOR: { // Operator is read - expecting a separator or operand
+ int ch = readNextChar();
+ if (ch == -1) {
+ return ELToken.EOF;
+ }
+ releaseChar();
+ if (Character.isJavaIdentifierPart((char)ch)) {
+ return readOperandOrReservedWordToken();
+ }
+ if (ch == ' ') {
+ return readSeparatorToken();
+ }
+ return ELToken.EOF;
+ }
+ case STATE_SEPARATOR: { // Separator is read - expecting a operand or operator
+ int ch = readNextChar();
+ if (ch == -1) {
+ return ELToken.EOF;
+ }
+ releaseChar();
+ if (Character.isJavaIdentifierPart((char)ch)) {
+ return readOperandOrReservedWordToken();
+ }
+ if (OPERATOR_SYMBOLS.indexOf(ch)>-1) {
+ return readOperatorToken();
+ }
+ releaseChar();
+ return ELToken.EOF;
+ }
+ }
+ return ELToken.EOF;
+ }
+
+ /*
+ * Returns the CharSequence object
+ *
+ * @param start
+ * @param length
+ * @return
+ */
+ private CharSequence getCharSequence(int start, int length) {
+ String text = ""; //$NON-NLS-1$
+ try {
+ text = expression.substring(start, start + length);
+ } catch (StringIndexOutOfBoundsException e) {
+ SeamCorePlugin.getDefault().logError(e);
+ text = ""; // For sure //$NON-NLS-1$
+ }
+ return text.subSequence(0, text.length());
+ }
+
+ /*
+ * Reads and returns the operator token from the expression
+ * @return
+ */
+ private ELToken readOperatorToken() {
+ fState = STATE_OPERATOR;
+ int startOfToken = index;
+ int ch;
+ while((ch = readNextChar()) != -1) {
+ if (OPERATOR_SYMBOLS.indexOf(ch)==-1) {
+ break;
+ }
+ }
+ releaseChar();
+ int length = index - startOfToken;
+ return (length > 0 ? new ELToken(startOfToken, length, getCharSequence(startOfToken,
length), ELToken.EL_OPERATOR_TOKEN) : ELToken.EOF);
+ }
+
+ /*
+ * Reads and returns the separator token from the expression
+ * @return
+ */
+ private ELToken readSeparatorToken() {
+ fState = STATE_SEPARATOR;
+ int startOfToken = index;
+ int ch;
+ while((ch = readNextChar()) != -1) {
+ if (ch!=' ') {
+ break;
+ }
+ }
+ releaseChar();
+ int length = index - startOfToken;
+ return (length > 0 ? new ELToken(startOfToken, length, getCharSequence(startOfToken,
length), ELToken.EL_SEPARATOR_TOKEN) : ELToken.EOF);
+ }
+
+ /*
+ * Reads and returns the operand token from the expression
+ * @return
+ */
+ private ELToken readOperandOrReservedWordToken() {
+ fState = STATE_OPERAND;
+ int startOfToken = index;
+ int ch;
+ while((ch = readNextChar()) != -1) {
+ if (!Character.isJavaIdentifierPart(ch) && ch!='.') {
+ break;
+ }
+ }
+ releaseChar();
+ int length = index - startOfToken;
+ boolean reservedWord = isResorvedWord(startOfToken, length);
+ int tokenType = ELToken.EL_OPERAND_TOKEN;
+ if(reservedWord) {
+ tokenType = ELToken.EL_RESERVED_WORD_TOKEN;
+ fState = STATE_RESERVED_WORD;
+ }
+
+ return (length > 0 ? new ELToken(startOfToken, length, getCharSequence(startOfToken,
length), tokenType) : ELToken.EOF);
+ }
+
+ private boolean isResorvedWord(String word) {
+ return RESERVED_WORDS.indexOf(" " + word.trim() + " ")>-1;
+ }
+
+ private boolean isResorvedWord(int beginIndex, int length) {
+ String word = expression.substring(beginIndex, beginIndex + length);
+ return isResorvedWord(word);
+ }
+
+ /* Reads the next character
+ * @return
+ */
+ private int readNextChar() {
+ int c = -1;
+ try {
+ if (index < expression.length()) {
+ c = expression.charAt(index);
+ }
+ } catch (StringIndexOutOfBoundsException e) {
+ SeamCorePlugin.getPluginLog().logError(e);
+ }
+ index++;
+ return c;
+ }
+
+ /*
+ * returns the character to the document
+ */
+ private void releaseChar() {
+ if (index > 0) {
+ index--;
+ }
+ }
+}
\ No newline at end of file
Modified:
trunk/seam/plugins/org.jboss.tools.seam.core/src/org/jboss/tools/seam/internal/core/validation/SeamELValidator.java
===================================================================
---
trunk/seam/plugins/org.jboss.tools.seam.core/src/org/jboss/tools/seam/internal/core/validation/SeamELValidator.java 2007-10-11
16:02:27 UTC (rev 4121)
+++
trunk/seam/plugins/org.jboss.tools.seam.core/src/org/jboss/tools/seam/internal/core/validation/SeamELValidator.java 2007-10-11
16:53:32 UTC (rev 4122)
@@ -13,6 +13,7 @@
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -48,7 +49,9 @@
import org.jboss.tools.seam.core.SeamCoreMessages;
import org.jboss.tools.seam.core.SeamCorePlugin;
import org.jboss.tools.seam.core.SeamPreferences;
+import org.jboss.tools.seam.internal.core.el.ELToken;
import org.jboss.tools.seam.internal.core.el.SeamELCompletionEngine;
+import org.jboss.tools.seam.internal.core.el.SeamELTokenizer;
/**
* EL Validator
@@ -220,7 +223,7 @@
// startEl = localString.indexOf("${");
// }
if(startEl>-1) {
- endEl = localString.indexOf('}', startEl);
+ endEl = localString.lastIndexOf('}');
if(endEl>-1) {
String value = localString.substring(startEl+2, endEl);
int os = offset + startEl + 2;
@@ -240,31 +243,44 @@
}
private void validateEl(IFile file, EL el) {
+ String exp = el.value;
+// String test = "hotelBooking.bookHotel(hotel.id, user.username) not null
av.test[] ! = var2 <> var3.test3";
+ SeamELTokenizer elTokenizer = new SeamELTokenizer(exp);
+ List<ELToken> tokens = elTokenizer.getTokens();
+ for (ELToken token : tokens) {
+ if(token.getType()==ELToken.EL_OPERAND_TOKEN) {
+ validateElOperand(file, token, el.getOffset());
+ }
+ }
+ }
+
+ private void validateElOperand(IFile file, ELToken operandToken, int documnetOffset) {
+ String operand = operandToken.getText();
try {
- String exp = el.value;
- int offset = exp.length();
+ int offset = operand.length();
+ if (!operand.endsWith(".")) { //$NON-NLS-1$
+ String prefix = SeamELCompletionEngine.getPrefix(operand, offset);
+ if(prefix!=null) {
+ int possition = operand.indexOf(prefix);
+ if (possition == -1) {
+ possition = 0;
+ }
- if (!exp.endsWith(".")) { //$NON-NLS-1$
- String prefix = SeamELCompletionEngine.getPrefix(exp, offset);
- if(prefix!=null) {
- int possition = exp.indexOf(prefix);
- if (possition == -1) possition = 0;
-
Set<ISeamContextVariable> usedVariables = new
HashSet<ISeamContextVariable>();
Map<String, IMethod> unpairedGettersOrSetters = new HashMap<String,
IMethod>();
-
- List<String> suggestions = engine.getCompletions(project, file, exp, prefix,
possition, true, usedVariables, unpairedGettersOrSetters);
-
+
+ List<String> suggestions = engine.getCompletions(project, file, operand,
prefix, possition, true, usedVariables, unpairedGettersOrSetters);
+
if(usedVariables.size()==0 && suggestions.size()==0) {
// Save resources with unknown variables names
validationContext.addUnnamedElResource(file.getFullPath());
} else {
// Save links between resource and used variables names
for(ISeamContextVariable variable: usedVariables) {
- validationContext.addLinkedElResource(variable.getName(),
file.getFullPath());
+ validationContext.addLinkedElResource(variable.getName(), file.getFullPath());
}
}
-
+
// Check pair for getter/setter
if(unpairedGettersOrSetters.size()>0) {
IMethod unpairedMethod = unpairedGettersOrSetters.values().iterator().next();
@@ -276,9 +292,9 @@
missingMethodName = existedMethodName;
existedMethodName =
SeamCoreMessages.getString("SEAM_EL_VALIDATOR_SETTER"); //$NON-NLS-1$
}
- addError(UNPAIRED_GETTER_OR_SETTER_MESSAGE_ID,
SeamPreferences.UNPAIRED_GETTER_OR_SETTER, new String[]{propertyName, existedMethodName,
missingMethodName}, el.getLength(), el.getOffset(), file);
+ addError(UNPAIRED_GETTER_OR_SETTER_MESSAGE_ID,
SeamPreferences.UNPAIRED_GETTER_OR_SETTER, new String[]{propertyName, existedMethodName,
missingMethodName}, operand.length(), documnetOffset, file);
}
-
+
if (suggestions != null && suggestions.size() > 0) {
// It's valid EL.
return;
@@ -291,16 +307,9 @@
SeamCorePlugin.getDefault().logError(SeamCoreMessages.getString("SEAM_EL_VALIDATOR_ERROR_VALIDATING_SEAM_EL"),
e); //$NON-NLS-1$
}
// Mark invalid EL
- addError(INVALID_EXPRESSION_MESSAGE_ID, SeamPreferences.INVALID_EXPRESSION, new
String[]{el.getValue()}, el.getLength(), el.getOffset(), file);
+ addError(INVALID_EXPRESSION_MESSAGE_ID, SeamPreferences.INVALID_EXPRESSION, new
String[]{operand}, operand.length(), documnetOffset + operandToken.getStart(), file);
}
- private IJavaProject getJavaProject() {
- if(javaProject == null) {
- javaProject = coreHelper.getJavaProject();
- }
- return javaProject;
- }
-
public static class EL {
private String value;
private int length;
Modified:
trunk/seam/plugins/org.jboss.tools.seam.core/src/org/jboss/tools/seam/internal/core/validation/messages.properties
===================================================================
---
trunk/seam/plugins/org.jboss.tools.seam.core/src/org/jboss/tools/seam/internal/core/validation/messages.properties 2007-10-11
16:02:27 UTC (rev 4121)
+++
trunk/seam/plugins/org.jboss.tools.seam.core/src/org/jboss/tools/seam/internal/core/validation/messages.properties 2007-10-11
16:53:32 UTC (rev 4122)
@@ -41,7 +41,7 @@
UNKNOWN_VARIABLE_NAME=Unknown context variable name: {0}
#Seam Expression language
-INVALID_EXPRESSION=Invalid Expression: {0}
+INVALID_EXPRESSION={0} cannot be resolved
UNPAIRED_GETTER_OR_SETTER=Property "{0}" has only {1}. {2} is missing.
#Messages for Progress Monitor
Modified:
trunk/seam/plugins/org.jboss.tools.seam.ui/src/org/jboss/tools/seam/ui/preferences/SeamPreferencesMessages.properties
===================================================================
---
trunk/seam/plugins/org.jboss.tools.seam.ui/src/org/jboss/tools/seam/ui/preferences/SeamPreferencesMessages.properties 2007-10-11
16:02:27 UTC (rev 4121)
+++
trunk/seam/plugins/org.jboss.tools.seam.ui/src/org/jboss/tools/seam/ui/preferences/SeamPreferencesMessages.properties 2007-10-11
16:53:32 UTC (rev 4122)
@@ -56,7 +56,7 @@
##Seam Expression language
SeamValidatorConfigurationBlock_section_el=Expression language
-SeamValidatorConfigurationBlock_pb_invalidExpression_label=Invalid Expression:
+SeamValidatorConfigurationBlock_pb_invalidExpression_label=Expression cannot be resolved
SeamValidatorConfigurationBlock_pb_unpairedGetterOrSetter_label=Unpaired Getter/Setter:
SEAM_VALIDATOR_CONFIGURATION_BLOCK_SEAM_VALIDATOR_CONFIGURATION_BLOCK=SeamValidatorConfigurationBlock
SEAM_VALIDATOR_CONFIGURATION_BLOCK_ERROR=Error