package processing.app.syntax;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author Jonathan Feinberg <jdf@pobox.com>
*
*/
public class Brackets {
private volatile List<Integer> offsets = null;
public void invalidate() {
offsets = null;
}
public int findMatchingBracket(final String text, final int pos) {
if (pos < 0 || pos >= text.length())
return -1;
final char alpha = text.charAt(pos);
final char beta;
final int direction;
switch (alpha) {
case '(':
beta = ')';
direction = 1;
break;
case ')':
beta = '(';
direction = -1;
break;
case '[':
beta = ']';
direction = 1;
break;
case ']':
beta = '[';
direction = -1;
break;
case '{':
beta = '}';
direction = 1;
break;
case '}':
beta = '{';
direction = -1;
break;
default:
return -1;
}
if (offsets == null)
parse(text);
// find this bracket
int p;
for (p = 0; p < offsets.size(); p++)
if (offsets.get(p) == pos)
break;
if (p == offsets.size()) {
return -1;
}
int depth = 1;
for (p += direction; p >= 0 && p < offsets.size(); p += direction) {
final int offset = offsets.get(p);
final char c = text.charAt(offset);
if (c == alpha)
depth++;
else if (c == beta)
depth--;
if (depth == 0)
return offset;
}
return -1;
}
int pos;
private void parse(final String text) {
offsets = new ArrayList<Integer>();
final int len = text.length();
for (pos = 0; pos < len; pos++) {
final char c = text.charAt(pos);
if (c == '/' && (pos < len - 1)) {
final char d = text.charAt(++pos);
if (d == '/') {
readComment(text);
} else if (d == '*') {
readMLComment(text);
} else pos--; // Go back because there isn't a comment.
} else if (c == '"' || c == '\'') {
readString(text, c);
} else if (c == '{' || c == '[' || c == '(' || c == '}' || c == ']'
|| c == ')') {
offsets.add(pos);
}
}
}
private void readString(final String text, final char q) {
final int len = text.length();
for (pos++; pos < len; pos++) {
final char c = text.charAt(pos);
if (c == q) {
return;
}
if (c == '\\') {
pos++;
}
}
}
private void readComment(final String text) {
final int len = text.length();
for (pos++; pos < len; pos++)
if (text.charAt(pos) == '\n') {
return;
}
}
private void readMLComment(final String text) {
final int len = text.length();
for (pos++; pos < len; pos++) {
final char c = text.charAt(pos);
if (c == '*' && (pos < len - 1)) {
final char d = text.charAt(pos + 1);
if (d == '/') {
pos++;
return;
}
}
}
}
}