Skip to content

Commit

Permalink
Merge branch 'master' into master-github
Browse files Browse the repository at this point in the history
  • Loading branch information
Sh18RW committed Nov 30, 2024
2 parents 54d0dd1 + 245b176 commit c4ff22a
Show file tree
Hide file tree
Showing 24 changed files with 425 additions and 246 deletions.
105 changes: 105 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
## Math Executor lib by Sh18RW
Here is a library to run as simple math expression like as `2 + 2` as `14 / (7 / (3 + (1 + (3/log(2, 4))) * 2 / 2 * 2) * (5 ^ 0 + 1))`.
### How to use
Library contains:
1. Parser class.
```java
public class App {
public static void main(String[] args) {
Parser parser = new Parser("14 / (7 / (3 + (1 + (3/log(2, 4))) * 2 / 2 * 2) * (5 ^ 0 + 1))");
try {
parser.parse();
} catch (ParserUnknownEntityException | ParserIllegalTokenValueException e) {
// process exceptions
}

List<Token<?>> result = parser.getResult();
// do something
}
}
```
It parses an input expression to List of tokens.
**It doesn't check for valid sequence.**
2. ExpressionTree class.
```java
public class App {
public static void process(List<Token<?>> tokens) {
ExpressionsTree expressionsTree = new ExpressionsTree(tokens);
try {
expressionsTree.build();
} catch (ExpressionException e) {
// process exception
}
Expression expression = expressionsTree.getRoot();
// do something
}
}
```
**Doesn't check for valid sequence at all. Only critical misspells.**
3. Calculator class.
```java
public class App {
public static void calculate(Expression expression) {
Calculator calculator = new Calculator();
double result;
try {
result = calculator.calculate((SequenceExpression) expression);
} catch (CalculatorException e) {
// process exception
}

System.out.println(result);
}
}
```
You needn't instantiate Calculator every use, you can make it once.
4. Number class, but I don't recommend you to use it.
```java
public class App {
public static void main(String[] args) {
System.out.println(
Numbers.getPrettierDoubleAsString(1.2345478, 4)
.equals("1.2345")); // true
System.out.println(Numbers.countTensNumbers(11234455.01246) == 8); // true
System.out.println(Numbers.countNumbersAfterPoint(1.100293) == 6); // true
System.out.println(Numbers.equals(12.0056, 12.0040, 0.01)); // true
System.out.println(Numbers.lessThan(12.09, 12.0, 0.1, true)); // true
}
}
```
### Example
```java
package ru.corvinella;

import ru.corvinella.expressions.ExpressionsTree;
import ru.corvinella.expressions.entries.SequenceExpression;
import ru.corvinella.expressions.exceptions.ExpressionException;
import ru.corvinella.math.Calculator;
import ru.corvinella.math.exceptions.CalculatorException;
import ru.corvinella.parser.Parser;
import ru.corvinella.parser.exceptions.ParserIllegalTokenValueException;
import ru.corvinella.parser.exceptions.ParserUnknownEntityException;

import java.util.Scanner;

public class App {
public static void main(String[] args) throws ParserIllegalTokenValueException, ParserUnknownEntityException, ExpressionException, CalculatorException {
Scanner scanner = new Scanner(System.in);
System.out.print("Please enter an expression: ");

String expression = scanner.nextLine();

Parser parser = new Parser(expression);
parser.parse();

ExpressionsTree expressionsTree = new ExpressionsTree(parser.getResult());
expressionsTree.build();

Calculator calculator = new Calculator();
double result = calculator.calculate((SequenceExpression) expressionsTree.getRoot());

System.out.printf("%s = %f%n", expression, result);
}
}
```
53 changes: 23 additions & 30 deletions src/main/java/ru/corvinella/expressions/ExpressionsTree.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package ru.corvinella.expressions;

import ru.corvinella.expressions.entries.*;
import ru.corvinella.expressions.exceptions.ExpressionException;
import ru.corvinella.expressions.exceptions.UnknownWordExpressionException;
import ru.corvinella.expressions.exceptions.WrongExpressionSequenceException;
import ru.corvinella.tokens.*;
import ru.corvinella.tokens.types.OperationType;
import ru.corvinella.tokens.types.ParenthesisType;
Expand All @@ -22,15 +25,15 @@ public ExpressionsTree(List<Token<?>> tokens) {
this.tokens = tokens;
}

public void build() {
public void build() throws ExpressionException {
for (Token<?> token: tokens) {
processToken(token);
}

root = expressionStates.get(0).pointer;
}

private void processToken(Token<?> token) {
private void processToken(Token<?> token) throws WrongExpressionSequenceException, UnknownWordExpressionException {
Expression expressionToAdd = null;
boolean appendExpression = true;
ExpressionState expressionState = getExpressionState();
Expand All @@ -46,8 +49,7 @@ private void processToken(Token<?> token) {
return;
}

// TODO: make expression tree exception
throw new IllegalStateException();
throw new WrongExpressionSequenceException("Waited for number, but got operator", token);
}

boolean appendOperation = true;
Expand Down Expand Up @@ -116,32 +118,23 @@ private void processToken(Token<?> token) {
} else {
WordToken wordToken = (WordToken) token;

switch (wordToken.getValue()) {
case Pi:
case E:
expressionToAdd = new ConstantExpression(wordToken);
break;
case Log:
case Sin:
case Cos:
case Tg:
case Ctg:
FunctionExpression functionExpression = new FunctionExpression(wordToken);
ArgumentsExpression argumentsExpression = new ArgumentsExpression();
ExpressionState argumentsState = new ExpressionState(argumentsExpression, ExpressionState.ReadingType.Argument);
expressionStates.add(argumentsState);
SequenceExpression sequenceExpression = new SequenceExpression();
ExpressionState newState = new ExpressionState(sequenceExpression, ExpressionState.ReadingType.Sum);
newState.ignoreOpenParenthesis = true;
expressionStates.add(newState);
argumentsExpression.appendExpression(sequenceExpression);

functionExpression.addArguments(argumentsExpression);
expressionToAdd = functionExpression;
break;
default:
// TODO: a normal exception
throw new IllegalStateException();
if (FunctionExpression.supportedFunctions.contains(wordToken.getValue())) {
FunctionExpression functionExpression = new FunctionExpression(wordToken);
ArgumentsExpression argumentsExpression = new ArgumentsExpression(wordToken);
ExpressionState argumentsState = new ExpressionState(argumentsExpression, ExpressionState.ReadingType.Argument);
expressionStates.add(argumentsState);
SequenceExpression sequenceExpression = new SequenceExpression();
ExpressionState newState = new ExpressionState(sequenceExpression, ExpressionState.ReadingType.Sum);
newState.ignoreOpenParenthesis = true;
expressionStates.add(newState);
argumentsExpression.appendExpression(sequenceExpression);

functionExpression.addArguments(argumentsExpression);
expressionToAdd = functionExpression;
} else if (ConstantExpression.supportedConstants.contains(wordToken.getValue())) {
expressionToAdd = new ConstantExpression(wordToken);
} else {
throw new UnknownWordExpressionException(wordToken);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package ru.corvinella.expressions.entries;

import ru.corvinella.tokens.ParenthesisToken;
import ru.corvinella.tokens.Token;

import java.util.LinkedList;
import java.util.List;

Expand All @@ -8,9 +11,11 @@
*/
public class ArgumentsExpression extends Expression {
private final List<Expression> arguments;
private final Token<?> token;

public ArgumentsExpression() {
public ArgumentsExpression(Token<?> token) {
this.arguments = new LinkedList<>();
this.token = token;
}

public final void appendExpression(Expression valueExpression) {
Expand All @@ -25,6 +30,10 @@ public final Expression getArgument(int index) {
return arguments.get(index);
}

public Token<?> getToken() {
return token;
}

@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,26 @@

import ru.corvinella.tokens.WordToken;

import java.util.Arrays;
import java.util.List;

/**
* @author sh18rw
*/
public class ConstantExpression extends ValueExpression {
private final Constant constantType;
public static final List<String> supportedConstants = Arrays.asList("pi", "e");
private final WordToken token;

public ConstantExpression(WordToken wordToken) {
this.token = wordToken;

switch (wordToken.getValue()) {
case Pi:
constantType = Constant.Pi;
break;
case E:
constantType = Constant.E;
break;
default:
throw new IllegalStateException(
String.format("For some reason there is no realisation for %s constant.", token.getValue()));
if (!supportedConstants.contains(token.getValue())) {
throw new IllegalStateException("Developer not implemented all constants, please contact them and rollback version until it is fixed.");
}
}

public Constant getConstantType() {
return constantType;
public String getConstantName() {
return token.getValue();
}

@Override
Expand All @@ -37,11 +32,6 @@ public boolean equals(Object obj) {

ConstantExpression constantExpression = (ConstantExpression) obj;

return constantExpression.constantType == this.constantType;
}

public enum Constant {
Pi,
E,
return constantExpression.getConstantName().equals(this.getConstantName());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,32 @@

import ru.corvinella.tokens.WordToken;

import java.util.Arrays;
import java.util.List;

/**
* @author sh18rw
*/
public class FunctionExpression extends ValueExpression {
private final Function functionType;
public static final List<String> supportedFunctions = Arrays.asList("log", "sin", "tg", "ctg");

private final WordToken token;
private ArgumentsExpression arguments;

public FunctionExpression(WordToken token) {
this.token = token;

switch (token.getValue()) {
case Log:
functionType = Function.Log;
break;
case Sin:
functionType = Function.Sin;
break;
case Cos:
functionType = Function.Cos;
break;
case Tg:
functionType = Function.Tg;
break;
case Ctg:
functionType = Function.Ctg;
default:
throw new IllegalStateException(
String.format("For some reason there is no realisation for %s function.", token.getValue()));
if (!supportedFunctions.contains(token.getValue())) {
throw new IllegalStateException("Developer not implemented all functions, please contact them and rollback version until it is fixed.");
}
}

public void addArguments(ArgumentsExpression argumentsExpression) {
this.arguments = argumentsExpression;
}

public Function getFunctionType() {
return functionType;
public String getFunctionName() {
return token.getValue();
}

public ArgumentsExpression getArguments() {
Expand All @@ -54,23 +42,15 @@ public boolean equals(Object obj) {

FunctionExpression functionExpression = (FunctionExpression) obj;

return functionExpression.functionType.equals(this.functionType)
return functionExpression.getFunctionName().equals(this.getFunctionName())
&& functionExpression.arguments.equals(this.arguments);
}

@Override
public String toString() {
return "Function["
+ functionType
+ getFunctionName()
+ " "
+ arguments.toString();
}

public enum Function {
Log,
Sin,
Cos,
Tg,
Ctg
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package ru.corvinella.expressions.exceptions;

import ru.corvinella.tokens.Token;
import ru.corvinella.utils.exceptions.ExceptionAtToken;

public abstract class ExpressionException extends Exception {
public abstract class ExpressionException extends ExceptionAtToken {
public ExpressionException(String message, Token<?> atToken) {
super(String.format("%s at %d, token %s.", message, atToken.getTracer(), atToken));
super(String.format("%s at %d, token %s.", message, atToken.getTracer(), atToken), atToken);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package ru.corvinella.expressions.exceptions;

import ru.corvinella.tokens.Token;
import ru.corvinella.tokens.WordToken;

/**
* @author sh18rw
*/
public class UnknownWordExpressionException extends ExpressionException {
public UnknownWordExpressionException(WordToken atToken) {
super("Unknown word token", atToken);
}
}
Loading

0 comments on commit c4ff22a

Please sign in to comment.