org.jparsec.examples.sql.parser.ExpressionParser Maven / Gradle / Ivy
The newest version!
/*****************************************************************************
* Copyright (C) jparsec.org *
* ------------------------------------------------------------------------- *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
*****************************************************************************/
package org.jparsec.examples.sql.parser;
import static org.jparsec.examples.sql.parser.TerminalParser.phrase;
import static org.jparsec.examples.sql.parser.TerminalParser.term;
import java.util.List;
import java.util.function.BinaryOperator;
import java.util.function.UnaryOperator;
import org.jparsec.OperatorTable;
import org.jparsec.Parser;
import org.jparsec.Parsers;
import org.jparsec.examples.sql.ast.BetweenExpression;
import org.jparsec.examples.sql.ast.BinaryExpression;
import org.jparsec.examples.sql.ast.BinaryRelationalExpression;
import org.jparsec.examples.sql.ast.Expression;
import org.jparsec.examples.sql.ast.FullCaseExpression;
import org.jparsec.examples.sql.ast.FunctionExpression;
import org.jparsec.examples.sql.ast.LikeExpression;
import org.jparsec.examples.sql.ast.NullExpression;
import org.jparsec.examples.sql.ast.NumberExpression;
import org.jparsec.examples.sql.ast.Op;
import org.jparsec.examples.sql.ast.QualifiedName;
import org.jparsec.examples.sql.ast.QualifiedNameExpression;
import org.jparsec.examples.sql.ast.Relation;
import org.jparsec.examples.sql.ast.SimpleCaseExpression;
import org.jparsec.examples.sql.ast.StringExpression;
import org.jparsec.examples.sql.ast.TupleExpression;
import org.jparsec.examples.sql.ast.UnaryExpression;
import org.jparsec.examples.sql.ast.UnaryRelationalExpression;
import org.jparsec.examples.sql.ast.WildcardExpression;
import org.jparsec.functors.Pair;
/**
* Parser for expressions.
*
* @author Ben Yu
*/
public final class ExpressionParser {
static final Parser NULL = term("null").retn(NullExpression.instance);
static final Parser NUMBER = TerminalParser.NUMBER.map(NumberExpression::new);
static final Parser QUALIFIED_NAME = TerminalParser.QUALIFIED_NAME
.map(QualifiedNameExpression::new);
static final Parser QUALIFIED_WILDCARD = TerminalParser.QUALIFIED_NAME
.followedBy(phrase(". *"))
.map(WildcardExpression::new);
static final Parser WILDCARD =
term("*").retn(new WildcardExpression(QualifiedName.of()))
.or(QUALIFIED_WILDCARD);
static final Parser STRING = TerminalParser.STRING.map(StringExpression::new);
static Parser functionCall(Parser param) {
return Parsers.sequence(
TerminalParser.QUALIFIED_NAME, paren(param.sepBy(TerminalParser.term(","))),
FunctionExpression::new);
}
static Parser tuple(Parser expr) {
return paren(expr.sepBy(term(","))).map(TupleExpression::new);
}
static Parser simpleCase(Parser expr) {
return Parsers.sequence(
term("case").next(expr),
whenThens(expr, expr),
term("else").next(expr).optional().followedBy(term("end")),
SimpleCaseExpression::new);
}
static Parser fullCase(Parser cond, Parser expr) {
return Parsers.sequence(
term("case").next(whenThens(cond, expr)),
term("else").next(expr).optional().followedBy(term("end")),
FullCaseExpression::new);
}
private static Parser>> whenThens(
Parser cond, Parser expr) {
return Parsers.pair(term("when").next(cond), term("then").next(expr)).many1();
}
static Parser paren(Parser parser) {
return parser.between(term("("), term(")"));
}
static Parser arithmetic(Parser atom) {
Parser.Reference reference = Parser.newReference();
Parser operand =
Parsers.or(paren(reference.lazy()), functionCall(reference.lazy()), atom);
Parser parser = new OperatorTable()
.infixl(binary("+", Op.PLUS), 10)
.infixl(binary("-", Op.MINUS), 10)
.infixl(binary("*", Op.MUL), 20)
.infixl(binary("/", Op.DIV), 20)
.infixl(binary("%", Op.MOD), 20)
.prefix(unary("-", Op.NEG), 50)
.build(operand);
reference.set(parser);
return parser;
}
static Parser expression(Parser cond) {
Parser.Reference reference = Parser.newReference();
Parser lazyExpr = reference.lazy();
Parser atom = Parsers.or(
NUMBER, WILDCARD, QUALIFIED_NAME, simpleCase(lazyExpr), fullCase(cond, lazyExpr));
Parser expression = arithmetic(atom).label("expression");
reference.set(expression);
return expression;
}
/************************** boolean expressions ****************************/
static Parser compare(Parser expr) {
return Parsers.or(
compare(expr, ">", Op.GT), compare(expr, ">=", Op.GE),
compare(expr, "<", Op.LT), compare(expr, "<=", Op.LE),
compare(expr, "=", Op.EQ), compare(expr, "<>", Op.NE),
nullCheck(expr), like(expr), between(expr));
}
static Parser like(Parser expr) {
return Parsers.sequence(
expr, Parsers.or(term("like").retn(true), phrase("not like").retn(false)),
expr, term("escape").next(expr).optional(),
LikeExpression::new);
}
static Parser nullCheck(Parser expr) {
return Parsers.sequence(
expr, phrase("is not").retn(Op.NOT).or(phrase("is").retn(Op.IS)), NULL,
BinaryExpression::new);
}
static Parser logical(Parser expr) {
Parser.Reference ref = Parser.newReference();
Parser parser = new OperatorTable()
.prefix(unary("not", Op.NOT), 30)
.infixl(binary("and", Op.AND), 20)
.infixl(binary("or", Op.OR), 10)
.build(paren(ref.lazy()).or(expr)).label("logical expression");
ref.set(parser);
return parser;
}
static Parser between(Parser expr) {
return Parsers.sequence(
expr, Parsers.or(term("between").retn(true), phrase("not between").retn(false)),
expr, term("and").next(expr),
BetweenExpression::new);
}
static Parser exists(Parser relation) {
return term("exists").next(relation).map(e -> new UnaryRelationalExpression(e, Op.EXISTS));
}
static Parser notExists(Parser relation) {
return phrase("not exists").next(relation)
.map(e -> new UnaryRelationalExpression(e, Op.NOT_EXISTS));
}
static Parser inRelation(Parser expr, Parser relation) {
return Parsers.sequence(
expr, Parsers.between(phrase("in ("), relation, term(")")),
(e, r) -> new BinaryRelationalExpression(e, Op.IN, r));
}
static Parser notInRelation(Parser expr, Parser relation) {
return Parsers.sequence(
expr, Parsers.between(phrase("not in ("), relation, term(")")),
(e, r) -> new BinaryRelationalExpression(e, Op.NOT_IN, r));
}
static Parser in(Parser expr) {
return Parsers.sequence(
expr, term("in").next(tuple(expr)),
(e, t) -> new BinaryExpression(e, Op.IN, t));
}
static Parser notIn(Parser expr) {
return Parsers.sequence(
expr, phrase("not in").next(tuple(expr)),
(e, t) -> new BinaryExpression(e, Op.NOT_IN, t));
}
static Parser condition(Parser expr, Parser rel) {
Parser atom = Parsers.or(
compare(expr), in(expr), notIn(expr),
exists(rel), notExists(rel), inRelation(expr, rel), notInRelation(expr, rel));
return logical(atom);
}
/************************** utility methods ****************************/
private static Parser compare(
Parser operand, String name, Op op) {
return Parsers.sequence(
operand, term(name).retn(op), operand,
BinaryExpression::new);
}
private static Parser> binary(String name, Op op) {
return term(name).retn((l, r) -> new BinaryExpression(l, op, r));
}
private static Parser> unary(String name, Op op) {
return term(name).retn(e -> new UnaryExpression(op, e));
}
}