org.n3r.eql.spec.SpecParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eql Show documentation
Show all versions of eql Show documentation
a simple wrapper framework for jdbc to seperate sql and java code
package org.n3r.eql.spec;
import java.util.ArrayList;
import java.util.List;
import static java.lang.Character.*;
public class SpecParser {
public static Spec parseSpecLeniently(String spec) {
Spec[] specs = parseSpecs(spec);
return specs.length == 0 ? null : specs[0];
}
public static Spec parseSpec(String spec) {
Spec[] specs = parseSpecs(spec);
if (specs.length > 1) {
throw new RuntimeException("too many spec defined");
}
return specs.length == 0 ? null : specs[0];
}
public static Spec[] parseSpecs(String specs) {
char[] chars = specs.toCharArray();
SpecState specState = SpecState.SpecClose;
StringBuilder name = new StringBuilder();
StringBuilder param = new StringBuilder();
ParamQuoteState paramQuoteState = ParamQuoteState.None;
ArrayList specsDefs = new ArrayList();
Spec spec = null;
int i = 0;
char ch = ' ';
for (int ii = chars.length; i < ii; ++i) {
ch = chars[i];
switch (specState) {
case SpecClose:
if (ch == '@') {
specState = SpecState.SpecOpen;
paramQuoteState = ParamQuoteState.None;
} else if (!isWhitespace(ch)) error(specs, i, ch);
break;
case SpecOpen:
if (isJavaIdentifierStart(ch)) {
specState = SpecState.SpecName;
name.append(ch);
} else error(specs, i, ch);
break;
case SpecName:
if (isJavaIdentifierPart(ch) || ch == '.' || ch == '$') name.append(ch);
else if (isWhitespace(ch) || ch == '@' || ch == '(') {
while (i < ii && isWhitespace(chars[i])) ++i;
if (i < ii) ch = chars[i];
specState = ch == '(' ? SpecState.ParamOpen : SpecState.SpecClose;
spec = addSpec(name, specsDefs);
if (specState == SpecState.SpecClose) --i; // backspace and continue
} else error(specs, i, ch);
break;
case ParamOpen:
switch (ch) {
case ')':
addSpecParam(param, paramQuoteState, spec);
specState = SpecState.SpecClose;
break;
case '"':
paramQuoteState = ParamQuoteState.Left;
specState = SpecState.ParamValue;
clear(param);
break;
case '\\':
ch = convertpecialChar(chars[++i]);
default:
if (!isWhitespace(ch)) {
param.append(ch);
specState = SpecState.ParamValue;
}
}
break;
case ParamValue:
switch (ch) {
case ')':
if (paramQuoteState == ParamQuoteState.Left) param.append(ch);
else {
addSpecParam(param, paramQuoteState, spec);
specState = SpecState.SpecClose;
}
break;
case ',':
if (paramQuoteState == ParamQuoteState.Left) param.append(ch);
else {
addSpecParam(param, paramQuoteState, spec);
paramQuoteState = ParamQuoteState.None;
specState = SpecState.ParamOpen;
}
break;
case '"':
if (paramQuoteState == ParamQuoteState.Left)
paramQuoteState = ParamQuoteState.Right;
else error(specs, i, ch);
break;
case '\\':
ch = convertpecialChar(chars[++i]);
default:
if (paramQuoteState == ParamQuoteState.Right) {
if (!isWhitespace(ch)) error(specs, i, ch);
} else param.append(ch);
}
break;
default:
error(specs, i, ch);
}
}
// Check whether it is normal ended
switch (specState) {
case SpecName:
addSpec(name, specsDefs);
break;
case SpecOpen:
case ParamValue:
case ParamOpen:
error(specs, i, ch);
}
return specsDefs.toArray(new Spec[0]);
}
private static Spec addSpec(StringBuilder name, List specsDefs) {
Spec spec = new Spec();
spec.setName(name.toString());
clear(name);
specsDefs.add(spec);
return spec;
}
private static void addSpecParam(StringBuilder param, ParamQuoteState paramInQuote, Spec spec) {
spec.addParam(paramInQuote == ParamQuoteState.Right ? param.toString() : trimSubstring(param));
clear(param);
}
private static StringBuilder clear(StringBuilder param) {
return param.delete(0, param.length());
}
public static String trimSubstring(StringBuilder sb) {
int first = 0, last = sb.length();
for (int ii = sb.length(); first < ii; first++)
if (!isWhitespace(sb.charAt(first))) break;
for (; last > first; last--)
if (!isWhitespace(sb.charAt(last - 1))) break;
return sb.substring(first, last);
}
private static Spec[] error(String specs, int i, char ch) {
throw new RuntimeException(specs + " is invalid at pos " + i + " with char " + ch);
}
private static char convertpecialChar(char aChar) {
switch (aChar) {
case 'n':
return '\n';
case 'r':
return '\r';
case 't':
return '\t';
case 'b':
return '\b';
case 'f':
return '\f';
}
return aChar;
}
private enum SpecState {SpecOpen, SpecName, ParamOpen, ParamValue, SpecClose}
private enum ParamQuoteState {None, Left, Right}
}