// see http://snowball.tartarus.org/
package divconq.lang.stem;
import java.lang.reflect.InvocationTargetException;
abstract public class Snowball {
protected Snowball() {
current = new StringBuffer();
setCurrent("");
}
protected Snowball(String word) {
current = new StringBuffer();
setCurrent(word);
}
public abstract boolean stem();
/*
* Set the current string.
*/
public void setCurrent(String value) {
current.replace(0, current.length(), value);
cursor = 0;
limit = current.length();
limit_backward = 0;
bra = cursor;
ket = limit;
}
/*
* Get the current string.
*/
public String getCurrent() {
String result = current.toString();
// Make a new StringBuffer. If we reuse the old one, and a user of
// the library keeps a reference to the buffer returned (for example,
// by converting it to a String in a way which doesn't force a copy),
// the buffer size will not decrease, and we will risk wasting a large
// amount of memory.
// Thanks to Wolfram Esser for spotting this problem.
current = new StringBuffer();
return result;
}
// current string
protected StringBuffer current;
protected int cursor;
protected int limit;
protected int limit_backward;
protected int bra;
protected int ket;
protected void copy_from(Snowball other) {
current = other.current;
cursor = other.cursor;
limit = other.limit;
limit_backward = other.limit_backward;
bra = other.bra;
ket = other.ket;
}
protected boolean in_grouping(char[] s, int min, int max) {
if (cursor >= limit)
return false;
char ch = current.charAt(cursor);
if (ch > max || ch < min)
return false;
ch -= min;
if ((s[ch >> 3] & (0X1 << (ch & 0X7))) == 0)
return false;
cursor++;
return true;
}
protected boolean in_grouping_b(char[] s, int min, int max) {
if (cursor <= limit_backward)
return false;
char ch = current.charAt(cursor - 1);
if (ch > max || ch < min)
return false;
ch -= min;
if ((s[ch >> 3] & (0X1 << (ch & 0X7))) == 0)
return false;
cursor--;
return true;
}
protected boolean out_grouping(char[] s, int min, int max) {
if (cursor >= limit)
return false;
char ch = current.charAt(cursor);
if (ch > max || ch < min) {
cursor++;
return true;
}
ch -= min;
if ((s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) {
cursor++;
return true;
}
return false;
}
protected boolean out_grouping_b(char[] s, int min, int max) {
if (cursor <= limit_backward)
return false;
char ch = current.charAt(cursor - 1);
if (ch > max || ch < min) {
cursor--;
return true;
}
ch -= min;
if ((s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) {
cursor--;
return true;
}
return false;
}
protected boolean in_range(int min, int max) {
if (cursor >= limit)
return false;
char ch = current.charAt(cursor);
if (ch > max || ch < min)
return false;
cursor++;
return true;
}
protected boolean in_range_b(int min, int max) {
if (cursor <= limit_backward)
return false;
char ch = current.charAt(cursor - 1);
if (ch > max || ch < min)
return false;
cursor--;
return true;
}
protected boolean out_range(int min, int max) {
if (cursor >= limit)
return false;
char ch = current.charAt(cursor);
if (!(ch > max || ch < min))
return false;
cursor++;
return true;
}
protected boolean out_range_b(int min, int max) {
if (cursor <= limit_backward)
return false;
char ch = current.charAt(cursor - 1);
if (!(ch > max || ch < min))
return false;
cursor--;
return true;
}
protected boolean eq_s(int s_size, String s) {
if (limit - cursor < s_size)
return false;
int i;
for (i = 0; i != s_size; i++) {
if (current.charAt(cursor + i) != s.charAt(i))
return false;
}
cursor += s_size;
return true;
}
protected boolean eq_s_b(int s_size, String s) {
if (cursor - limit_backward < s_size)
return false;
int i;
for (i = 0; i != s_size; i++) {
if (current.charAt(cursor - s_size + i) != s.charAt(i))
return false;
}
cursor -= s_size;
return true;
}
protected boolean eq_v(CharSequence s) {
return eq_s(s.length(), s.toString());
}
protected boolean eq_v_b(CharSequence s) {
return eq_s_b(s.length(), s.toString());
}
protected int find_among(Among v[], int v_size) {
int i = 0;
int j = v_size;
int c = cursor;
int l = limit;
int common_i = 0;
int common_j = 0;
boolean first_key_inspected = false;
while (true) {
int k = i + ((j - i) >> 1);
int diff = 0;
int common = common_i < common_j ? common_i : common_j; // smaller
Among w = v[k];
int i2;
for (i2 = common; i2 < w.s_size; i2++) {
if (c + common == l) {
diff = -1;
break;
}
diff = current.charAt(c + common) - w.s[i2];
if (diff != 0)
break;
common++;
}
if (diff < 0) {
j = k;
common_j = common;
} else {
i = k;
common_i = common;
}
if (j - i <= 1) {
if (i > 0)
break; // v->s has been inspected
if (j == i)
break; // only one item in v
// - but now we need to go round once more to get
// v->s inspected. This looks messy, but is actually
// the optimal approach.
if (first_key_inspected)
break;
first_key_inspected = true;
}
}
while (true) {
Among w = v[i];
if (common_i >= w.s_size) {
cursor = c + w.s_size;
if (w.method == null)
return w.result;
boolean res;
try {
Object resobj = w.method.invoke(w.methodobject,
new Object[0]);
res = resobj.toString().equals("true");
} catch (InvocationTargetException e) {
res = false;
// FIXME - debug message
} catch (IllegalAccessException e) {
res = false;
// FIXME - debug message
}
cursor = c + w.s_size;
if (res)
return w.result;
}
i = w.substring_i;
if (i < 0)
return 0;
}
}
// find_among_b is for backwards processing. Same comments apply
protected int find_among_b(Among v[], int v_size) {
int i = 0;
int j = v_size;
int c = cursor;
int lb = limit_backward;
int common_i = 0;
int common_j = 0;
boolean first_key_inspected = false;
while (true) {
int k = i + ((j - i) >> 1);
int diff = 0;
int common = common_i < common_j ? common_i : common_j;
Among w = v[k];
int i2;
for (i2 = w.s_size - 1 - common; i2 >= 0; i2--) {
if (c - common == lb) {
diff = -1;
break;
}
diff = current.charAt(c - 1 - common) - w.s[i2];
if (diff != 0)
break;
common++;
}
if (diff < 0) {
j = k;
common_j = common;
} else {
i = k;
common_i = common;
}
if (j - i <= 1) {
if (i > 0)
break;
if (j == i)
break;
if (first_key_inspected)
break;
first_key_inspected = true;
}
}
while (true) {
Among w = v[i];
if (common_i >= w.s_size) {
cursor = c - w.s_size;
if (w.method == null)
return w.result;
boolean res;
try {
Object resobj = w.method.invoke(w.methodobject,
new Object[0]);
res = resobj.toString().equals("true");
} catch (InvocationTargetException e) {
res = false;
// FIXME - debug message
} catch (IllegalAccessException e) {
res = false;
// FIXME - debug message
}
cursor = c - w.s_size;
if (res)
return w.result;
}
i = w.substring_i;
if (i < 0)
return 0;
}
}
/*
* to replace chars between c_bra and c_ket in current by the chars in s.
*/
protected int replace_s(int c_bra, int c_ket, String s) {
int adjustment = s.length() - (c_ket - c_bra);
current.replace(c_bra, c_ket, s);
limit += adjustment;
if (cursor >= c_ket)
cursor += adjustment;
else if (cursor > c_bra)
cursor = c_bra;
return adjustment;
}
protected void slice_check() {
if (bra < 0 || bra > ket || ket > limit || limit > current.length()) // this
// line
// could
// be
// removed
{
System.err.println("faulty slice operation");
// FIXME: report error somehow.
/*
* fprintf(stderr, "faulty slice operation:\n"); debug(z, -1, 0);
* exit(1);
*/
}
}
protected void slice_from(String s) {
slice_check();
replace_s(bra, ket, s);
}
protected void slice_from(CharSequence s) {
slice_from(s.toString());
}
protected void slice_del() {
slice_from("");
}
protected void insert(int c_bra, int c_ket, String s) {
int adjustment = replace_s(c_bra, c_ket, s);
if (c_bra <= bra)
bra += adjustment;
if (c_bra <= ket)
ket += adjustment;
}
protected void insert(int c_bra, int c_ket, CharSequence s) {
insert(c_bra, c_ket, s.toString());
}
/* Copy the slice into the supplied StringBuffer */
protected StringBuffer slice_to(StringBuffer s) {
slice_check();
//int len = ket - bra;
s.replace(0, s.length(), current.substring(bra, ket));
return s;
}
/* Copy the slice into the supplied StringBuilder */
protected StringBuilder slice_to(StringBuilder s) {
slice_check();
//int len = ket - bra;
s.replace(0, s.length(), current.substring(bra, ket));
return s;
}
protected StringBuffer assign_to(StringBuffer s) {
s.replace(0, s.length(), current.substring(0, limit));
return s;
}
protected StringBuilder assign_to(StringBuilder s) {
s.replace(0, s.length(), current.substring(0, limit));
return s;
}
/*
* extern void debug(struct SN_env * z, int number, int line_count) { int i;
* int limit = SIZE(z->p); //if (number >= 0) printf("%3d (line %4d): '",
* number, line_count); if (number >= 0) printf("%3d (line %4d): [%d]'",
* number, line_count,limit); for (i = 0; i <= limit; i++) { if (z->lb == i)
* printf("{"); if (z->bra == i) printf("["); if (z->c == i) printf("|"); if
* (z->ket == i) printf("]"); if (z->l == i) printf("}"); if (i < limit) {
* int ch = z->p[i]; if (ch == 0) ch = '#'; printf("%c", ch); } }
* printf("'\n"); }
*/
};