public static MultiStatementNode parse(final String sql) throws ParseException {
Deque<CompositeNode> parents = new LinkedList<>();
parents.push(new MultiStatementNode(0));
parents.push(new StatementNode(0));
int paramId = 1;
int ndx = 0;
try {
while (ndx < sql.length()) {
char c = sql.charAt(ndx);
switch (c) {
case '\'':
ndx = consumeStringLiteral(sql, ndx + 1, parents.peek());
continue;
case '"':
ndx = consumeQuotedIdentifier(sql, ndx, parents.peek());
continue;
case '?':
ParameterPiece parameterPiece = new ParameterPiece(paramId++, ndx);
parents.peek().add(parameterPiece);
break;
case '$':
ndx = consumeDollar(sql, ndx, parents.peek());
continue;
case '(':
case ')':
ndx = consumeParens(sql, ndx, parents);
continue;
case '{':
case '}':
ndx = consumeBraces(sql, ndx, parents);
continue;
case '/':
if (lookAhead(sql, ndx) == '*') {
ndx = consumeMultilineComment(sql, ndx, parents.peek());
continue;
}
else {
parents.peek().add(new GrammarPiece("/", ndx));
break;
}
case '-':
if (lookAhead(sql, ndx) == '-') {
ndx = consumeSinglelineComment(sql, ndx, parents.peek());
continue;
}
else if (Character.isDigit(lookAhead(sql, ndx))) {
ndx = consumeNumeric(sql, ndx, parents.peek());
continue;
}
else {
GrammarPiece grammarPiece = new GrammarPiece("-", ndx);
parents.peek().add(grammarPiece);
break;
}
case ';':
if (parents.size() == 2) {
paramId = 1;
CompositeNode comp = parents.pop();
comp.setEndPos(ndx);
parents.peek().add(comp);
parents.push(new StatementNode(ndx));
}
else {
parents.peek().add(new GrammarPiece(";", ndx));
}
break;
default:
if (Character.isWhitespace(c)) {
WhitespacePiece whitespacePiece = new WhitespacePiece(sql.substring(ndx, ndx + 1), ndx);
if (parents.peek().getLastNode() instanceof WhitespacePiece) {
((WhitespacePiece) parents.peek().getLastNode()).coalesce(whitespacePiece);
}
else {
parents.peek().add(whitespacePiece);
}
}
else if (Character.isDigit(c) || (c == '+' && Character.isDigit(lookAhead(sql, ndx)))) {
ndx = consumeNumeric(sql, ndx, parents.peek());
continue;
}
else if (Character.isJavaIdentifierStart(c)) {
ndx = consumeUnquotedIdentifier(sql, ndx, parents.peek());
continue;
}
else {
GrammarPiece grammarPiece = new GrammarPiece(sql.substring(ndx, ndx + 1), ndx);
if (parents.peek().getLastNode() instanceof GrammarPiece) {
((GrammarPiece) parents.peek().getLastNode()).coalesce(grammarPiece);
}
else {
parents.peek().add(grammarPiece);
}
}
}
++ndx;
}
// Auto close last statement
if (parents.peek() instanceof StatementNode) {
StatementNode stmt = (StatementNode) parents.peek();
stmt.trim();
if (stmt.getNodeCount() > 0) {
CompositeNode tmp = parents.pop();
tmp.setEndPos(ndx);
parents.peek().add(tmp);
}
}