first commit

This commit is contained in:
me
2026-04-08 21:25:17 +03:00
parent 3681b8eccd
commit 371b14c5e3
173 changed files with 14126 additions and 0 deletions

View File

@@ -0,0 +1,239 @@
package expression.generic;
import java.util.List;
/**
* @author Doschennikov Nikita (me@fymio.us)
*/
public class GenericParser {
private static final List<String> VARIABLES = List.of("x", "y", "z");
private String src;
private int pos;
public <T> GenericExpr<T> parse(String expression) {
this.src = expression;
this.pos = 0;
GenericExpr<T> result = parseMinMax();
skipWhitespace();
if (pos < src.length()) {
throw new IllegalArgumentException(
"Unexpected character '" +
src.charAt(pos) +
"' at position " +
pos
);
}
return result;
}
private <T> GenericExpr<T> parseMinMax() {
GenericExpr<T> left = parseAddSub();
while (true) {
skipWhitespace();
if (matchKeyword("min")) {
GenericExpr<T> right = parseAddSub();
GenericExpr<T> l = left;
left = (type, vars) ->
type.min(
l.evaluate(type, vars),
right.evaluate(type, vars)
);
} else if (matchKeyword("max")) {
GenericExpr<T> right = parseAddSub();
GenericExpr<T> l = left;
left = (type, vars) ->
type.max(
l.evaluate(type, vars),
right.evaluate(type, vars)
);
} else {
break;
}
}
return left;
}
private <T> GenericExpr<T> parseAddSub() {
GenericExpr<T> left = parseMulDiv();
while (true) {
skipWhitespace();
if (pos < src.length() && src.charAt(pos) == '+') {
pos++;
GenericExpr<T> right = parseMulDiv();
GenericExpr<T> l = left;
left = (type, vars) ->
type.add(
l.evaluate(type, vars),
right.evaluate(type, vars)
);
} else if (
pos < src.length() && src.charAt(pos) == '-' && !nextIsKeyword()
) {
pos++;
GenericExpr<T> right = parseMulDiv();
GenericExpr<T> l = left;
left = (type, vars) ->
type.subtract(
l.evaluate(type, vars),
right.evaluate(type, vars)
);
} else {
break;
}
}
return left;
}
private <T> GenericExpr<T> parseMulDiv() {
GenericExpr<T> left = parseUnary();
while (true) {
skipWhitespace();
if (pos < src.length() && src.charAt(pos) == '*') {
pos++;
GenericExpr<T> right = parseUnary();
GenericExpr<T> l = left;
left = (type, vars) ->
type.multiply(
l.evaluate(type, vars),
right.evaluate(type, vars)
);
} else if (pos < src.length() && src.charAt(pos) == '/') {
pos++;
GenericExpr<T> right = parseUnary();
GenericExpr<T> l = left;
left = (type, vars) ->
type.divide(
l.evaluate(type, vars),
right.evaluate(type, vars)
);
} else {
break;
}
}
return left;
}
private <T> GenericExpr<T> parseUnary() {
skipWhitespace();
if (pos >= src.length()) {
throw new IllegalArgumentException(
"Unexpected end of expression at position " + pos
);
}
if (src.charAt(pos) == '-') {
pos++;
skipWhitespace();
if (pos < src.length() && Character.isDigit(src.charAt(pos))) {
return parseNumber(true);
}
GenericExpr<T> operand = parseUnary();
return (type, vars) -> type.negate(operand.evaluate(type, vars));
}
if (matchKeyword("count")) {
GenericExpr<T> operand = parseUnary();
return (type, vars) -> type.count(operand.evaluate(type, vars));
}
return parsePrimary();
}
private <T> GenericExpr<T> parsePrimary() {
skipWhitespace();
if (pos >= src.length()) {
throw new IllegalArgumentException("Unexpected end of expression");
}
char c = src.charAt(pos);
if (c == '(') {
pos++;
GenericExpr<T> inner = parseMinMax();
skipWhitespace();
expect();
return inner;
}
if (Character.isDigit(c)) {
return parseNumber(false);
}
if (Character.isLetter(c)) {
int start = pos;
while (
pos < src.length() && Character.isLetterOrDigit(src.charAt(pos))
) {
pos++;
}
String name = src.substring(start, pos);
int idx = VARIABLES.indexOf(name);
if (idx >= 0) {
return (type, vars) -> vars.get(idx);
}
throw new IllegalArgumentException(
"Unknown variable '" + name + "' at position " + start
);
}
throw new IllegalArgumentException(
"Unexpected character '" + c + "' at position " + pos
);
}
private <T> GenericExpr<T> parseNumber(boolean negative) {
int start = pos;
while (pos < src.length() && Character.isDigit(src.charAt(pos))) {
pos++;
}
if (start == pos) {
throw new IllegalArgumentException(
"Expected digit at position " + pos
);
}
String numStr = src.substring(start, pos);
long val = Long.parseLong(numStr);
if (negative) val = -val;
if (val < Integer.MIN_VALUE || val > Integer.MAX_VALUE) {
throw new IllegalArgumentException("Integer overflow: " + val);
}
int intVal = (int) val;
return (type, vars) -> type.fromInt(intVal);
}
private boolean matchKeyword(String keyword) {
int i = pos;
for (char ch : keyword.toCharArray()) {
if (i >= src.length() || src.charAt(i) != ch) return false;
i++;
}
if (
i < src.length() && Character.isLetterOrDigit(src.charAt(i))
) return false;
pos = i;
return true;
}
private boolean nextIsKeyword() {
return false;
}
private void skipWhitespace() {
while (pos < src.length() && Character.isWhitespace(src.charAt(pos))) {
pos++;
}
}
private void expect() {
if (pos >= src.length() || src.charAt(pos) != ')') {
throw new IllegalArgumentException(
"Expected '" +
')' +
"' at position " +
pos +
(pos < src.length()
? ", got '" + src.charAt(pos) + "'"
: ", got end of input")
);
}
pos++;
}
}