tokens.add(OPEN_TOKEN);
int colonPos = indexOf(expr, ":", i);
int closePos = indexOf(expr, "}", i);
int openPos = indexOf(expr, "{", i);
if (openPos < colonPos && openPos < closePos) {
throw new PatternException("Invalid '{' at position "+ i + " in expression " + expr);
} else if (colonPos < closePos) {
// we've found a module
Token token;
String module = expr.substring(i+1, colonPos);
if (module.equals("sitemap")) {
// Explicit prefix for sitemap variable
needsMapStack = true;
token = new Token(PREFIXED_SITEMAP_VAR);
} else if (module.startsWith("#")) {
// anchor syntax refering to a name result level
needsMapStack = true;
token = new Token(ANCHOR_VAR, module.substring(1));
} else {
// Module used
token = getNewModuleToken(module);
}
tokens.add(token);
i = colonPos-1;
} else {
// Unprefixed name : sitemap variable
needsMapStack = true;
tokens.add(getNewSitemapToken(expr.substring(i+1, closePos)));
i = closePos-1;
}
pos=i+1;
} else if (c=='}') {
if (i>0 && expr.charAt(i-1) == '\\') {
continue;
}
if (i> pos) {
tokens.add(new Token(expr.substring(pos, i)));
}
closeCount++;
tokens.add(CLOSE_TOKEN);
pos=i+1;
} else if (c==':') {
if (tokens.size()>0) {
int lastTokenType = ((Token)tokens.get(tokens.size()-1)).getType();
if (lastTokenType != PREFIXED_SITEMAP_VAR &&
lastTokenType != ANCHOR_VAR &&
lastTokenType != THREADSAFE_MODULE &&
lastTokenType != STATEFUL_MODULE) {
continue;
}
}
if (i != pos || tokens.size()==0) {
// this colon isn't part of a module reference
continue;
}
if (i> pos) {
tokens.add(new Token(expr.substring(pos, i)));
}
tokens.add(COLON_TOKEN);
pos=i+1;
}
}
if (i> pos) {
tokens.add(new Token(expr.substring(pos, i)));
}
if (openCount != closeCount) {
throw new PatternException("Mismatching braces in expression: " + expr);
}
}