1
0
mirror of https://github.com/DanilaFe/abacus synced 2026-01-27 09:05:19 +00:00

Compare commits

...

19 Commits

Author SHA1 Message Date
9fdb3fc0d9 Add an additional, restricted type of context for use only by plugins. 2017-11-23 13:29:06 -08:00
095d374949 Merge pull request #47 from DanilaFe/plugin-conversions
Move all the number reducer functionality into the context.
2017-11-14 23:22:01 -08:00
981211ccfa Merge branch 'master' into plugin-conversions 2017-11-14 23:18:18 -08:00
d91536e746 Merge pull request #48 from DanilaFe/documentation-fix
Fix crash when a TreeValueFunction doesn't have documentation loaded.
2017-11-14 23:18:09 -08:00
7c252fddf1 Merge branch 'master' into plugin-conversions 2017-11-14 23:13:51 -08:00
0d26167f31 Merge branch 'master' into documentation-fix 2017-11-14 23:13:44 -08:00
07abe4d17a Merge pull request #46 from DanilaFe/isint-idiom
Add and use isInteger function where appropriate.
2017-11-14 23:13:10 -08:00
8ef0904d26 Fix crash when a TreeValueFunction doesn't have documentation loaded. 2017-11-14 23:08:04 -08:00
92489551ca Move all the number reducer functionality into the context. 2017-11-14 23:03:12 -08:00
2a9026f748 Add and use isInteger function where appropriate. 2017-11-03 21:41:46 -07:00
08e5b69c04 Merge pull request #43 from DanilaFe/java8-subset
Replace some recent android API features with backwards compatible ones.
2017-09-24 13:04:23 -07:00
6a0b667c32 Replace some recent android API features with backwards compatible ones. 2017-09-24 12:58:33 -07:00
5a1fdfe4bc Merge pull request #42 from DanilaFe/java8-subset
Restrict Abacus core to a Java8 subset
2017-09-24 00:38:54 -07:00
378ff946d9 Add a Transformation class that replaces java.util.function use 2017-09-24 00:29:43 -07:00
0511c58b13 Remove the Pattern's dependency on java.util.function 2017-09-24 00:12:25 -07:00
e82a13cde5 Move ClassFinder to the fx module, which is the only place it's used. 2017-09-24 00:01:43 -07:00
40362a7afe Merge pull request #40 from DanilaFe/move-files
More around files into more applicable packages.
2017-09-23 23:46:02 -07:00
c990d4c50a More around files into more applicable packages. 2017-09-23 23:43:08 -07:00
d7bb838866 Merge pull request #39 from DanilaFe/more-kotlin
Switch more code to Kotlin
2017-09-23 23:03:23 -07:00
70 changed files with 467 additions and 334 deletions

View File

@@ -1,9 +1,8 @@
package org.nwapw.abacus.lexing; package org.nwapw.abacus.lexing;
import org.nwapw.abacus.lexing.pattern.EndNode;
import org.nwapw.abacus.lexing.pattern.Match;
import org.nwapw.abacus.lexing.pattern.Pattern; import org.nwapw.abacus.lexing.pattern.Pattern;
import org.nwapw.abacus.lexing.pattern.PatternNode; import org.nwapw.abacus.lexing.pattern.nodes.EndNode;
import org.nwapw.abacus.lexing.pattern.nodes.PatternNode;
import java.util.*; import java.util.*;
@@ -80,10 +79,10 @@ public class Lexer<T> {
index++; index++;
} }
matches.sort((a, b) -> compare.compare(a.getType(), b.getType()));
if (compare != null) { if (compare != null) {
matches.sort(Comparator.comparingInt(a -> a.getContent().length())); Collections.sort(matches, (a, b) -> compare.compare(a.getType(), b.getType()));
} }
Collections.sort(matches, (o1, o2) -> o1.getContent().length() - o2.getContent().length());
return matches.isEmpty() ? null : matches.get(matches.size() - 1); return matches.isEmpty() ? null : matches.get(matches.size() - 1);
} }
@@ -137,7 +136,10 @@ public class Lexer<T> {
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(name, id); return Arrays.hashCode(new Object[] {
this.name,
this.id
});
} }
@Override @Override

View File

@@ -1,4 +1,4 @@
package org.nwapw.abacus.lexing.pattern; package org.nwapw.abacus.lexing;
/** /**
* A match that has been generated by the lexer. * A match that has been generated by the lexer.

View File

@@ -1,10 +1,11 @@
package org.nwapw.abacus.lexing.pattern; package org.nwapw.abacus.lexing.pattern;
import org.nwapw.abacus.lexing.pattern.nodes.*;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Stack; import java.util.Stack;
import java.util.function.Function;
/** /**
* A pattern that can be compiled from a string and used in lexing. * A pattern that can be compiled from a string and used in lexing.
@@ -34,8 +35,8 @@ public class Pattern<T> {
* A map of regex operator to functions that modify a PatternChain * A map of regex operator to functions that modify a PatternChain
* with the appropriate operation. * with the appropriate operation.
*/ */
private Map<Character, Function<PatternChain<T>, PatternChain<T>>> operations = private Map<Character, Transformation<T>> operations =
new HashMap<Character, Function<PatternChain<T>, PatternChain<T>>>() {{ new HashMap<Character, Transformation<T>>() {{
put('+', Pattern.this::transformPlus); put('+', Pattern.this::transformPlus);
put('*', Pattern.this::transformStar); put('*', Pattern.this::transformStar);
put('?', Pattern.this::transformQuestion); put('?', Pattern.this::transformQuestion);
@@ -88,7 +89,7 @@ public class Pattern<T> {
* @return the modified chain. * @return the modified chain.
*/ */
private PatternChain<T> transformPlus(PatternChain<T> chain) { private PatternChain<T> transformPlus(PatternChain<T> chain) {
chain.tail.outputStates.add(chain.head); chain.tail.getOutputStates().add(chain.head);
return chain; return chain;
} }
@@ -102,10 +103,10 @@ public class Pattern<T> {
private PatternChain<T> transformStar(PatternChain<T> chain) { private PatternChain<T> transformStar(PatternChain<T> chain) {
LinkNode<T> newTail = new LinkNode<>(); LinkNode<T> newTail = new LinkNode<>();
LinkNode<T> newHead = new LinkNode<>(); LinkNode<T> newHead = new LinkNode<>();
newHead.outputStates.add(chain.head); newHead.getOutputStates().add(chain.head);
newHead.outputStates.add(newTail); newHead.getOutputStates().add(newTail);
chain.tail.outputStates.add(newTail); chain.tail.getOutputStates().add(newTail);
newTail.outputStates.add(newHead); newTail.getOutputStates().add(newHead);
chain.head = newHead; chain.head = newHead;
chain.tail = newTail; chain.tail = newTail;
return chain; return chain;
@@ -121,9 +122,9 @@ public class Pattern<T> {
private PatternChain<T> transformQuestion(PatternChain<T> chain) { private PatternChain<T> transformQuestion(PatternChain<T> chain) {
LinkNode<T> newTail = new LinkNode<>(); LinkNode<T> newTail = new LinkNode<>();
LinkNode<T> newHead = new LinkNode<>(); LinkNode<T> newHead = new LinkNode<>();
newHead.outputStates.add(chain.head); newHead.getOutputStates().add(chain.head);
newHead.outputStates.add(newTail); newHead.getOutputStates().add(newTail);
chain.tail.outputStates.add(newTail); chain.tail.getOutputStates().add(newTail);
chain.head = newHead; chain.head = newHead;
chain.tail = newTail; chain.tail = newTail;
return chain; return chain;
@@ -140,8 +141,8 @@ public class Pattern<T> {
LinkNode<T> tail = new LinkNode<>(); LinkNode<T> tail = new LinkNode<>();
PatternChain<T> newChain = new PatternChain<>(head, tail); PatternChain<T> newChain = new PatternChain<>(head, tail);
for (PatternChain<T> chain : collection) { for (PatternChain<T> chain : collection) {
head.outputStates.add(chain.head); head.getOutputStates().add(chain.head);
chain.tail.outputStates.add(tail); chain.tail.getOutputStates().add(tail);
} }
return newChain; return newChain;
} }
@@ -205,7 +206,7 @@ public class Pattern<T> {
if (operations.containsKey(currentChar)) { if (operations.containsKey(currentChar)) {
if (currentChain == null) return null; if (currentChain == null) return null;
currentChain = operations.get(currentChar).apply(currentChain); currentChain = operations.get(currentChar).transform(currentChain);
fullChain.append(currentChain); fullChain.append(currentChain);
currentChain = null; currentChain = null;
index++; index++;

View File

@@ -1,5 +1,7 @@
package org.nwapw.abacus.lexing.pattern; package org.nwapw.abacus.lexing.pattern;
import org.nwapw.abacus.lexing.pattern.nodes.PatternNode;
/** /**
* A chain of nodes that can be treated as a single unit. * A chain of nodes that can be treated as a single unit.
* Used during pattern compilation. * Used during pattern compilation.
@@ -56,7 +58,7 @@ public class PatternChain<T> {
this.head = other.head; this.head = other.head;
this.tail = other.tail; this.tail = other.tail;
} else { } else {
tail.outputStates.add(other.head); tail.getOutputStates().add(other.head);
tail = other.tail; tail = other.tail;
} }
} }
@@ -72,7 +74,7 @@ public class PatternChain<T> {
if (tail == null) { if (tail == null) {
head = tail = node; head = tail = node;
} else { } else {
tail.outputStates.add(node); tail.getOutputStates().add(node);
tail = node; tail = node;
} }
} }

View File

@@ -0,0 +1,16 @@
package org.nwapw.abacus.lexing.pattern;
/**
* An interface that transforms a pattern chain into a different pattern chain.
* @param <T> the type used to identify the nodes in the pattern chain.
*/
public interface Transformation<T> {
/**
* Performs the actual transformation.
* @param from the original chain.
* @return the resulting chain.
*/
PatternChain<T> transform(PatternChain<T> from);
}

View File

@@ -1,4 +1,4 @@
package org.nwapw.abacus.lexing.pattern; package org.nwapw.abacus.lexing.pattern.nodes;
/** /**
* A pattern node that matches any character. * A pattern node that matches any character.

View File

@@ -1,4 +1,4 @@
package org.nwapw.abacus.lexing.pattern; package org.nwapw.abacus.lexing.pattern.nodes;
/** /**
* A node that represents a successful match. * A node that represents a successful match.

View File

@@ -1,4 +1,4 @@
package org.nwapw.abacus.lexing.pattern; package org.nwapw.abacus.lexing.pattern.nodes;
import java.util.Collection; import java.util.Collection;

View File

@@ -1,4 +1,4 @@
package org.nwapw.abacus.lexing.pattern; package org.nwapw.abacus.lexing.pattern.nodes;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
@@ -65,4 +65,11 @@ public class PatternNode<T> {
outputStates.forEach(e -> e.addInto(into)); outputStates.forEach(e -> e.addInto(into));
} }
/**
* Gets the output states of this node.
* @return the output states.
*/
public Set<PatternNode<T>> getOutputStates() {
return outputStates;
}
} }

View File

@@ -1,4 +1,4 @@
package org.nwapw.abacus.lexing.pattern; package org.nwapw.abacus.lexing.pattern.nodes;
/** /**
* A node that matches a range of characters. * A node that matches a range of characters.

View File

@@ -1,4 +1,4 @@
package org.nwapw.abacus.lexing.pattern; package org.nwapw.abacus.lexing.pattern.nodes;
/** /**
* A node that matches a single value. * A node that matches a single value.

View File

@@ -1,4 +1,6 @@
package org.nwapw.abacus.number; package org.nwapw.abacus.number.standard;
import org.nwapw.abacus.number.NumberInterface;
/** /**
* An implementation of NumberInterface using a double. * An implementation of NumberInterface using a double.

View File

@@ -1,4 +1,6 @@
package org.nwapw.abacus.number; package org.nwapw.abacus.number.standard;
import org.nwapw.abacus.number.NumberInterface;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.MathContext; import java.math.MathContext;

View File

@@ -1,12 +1,12 @@
package org.nwapw.abacus.parsing; package org.nwapw.abacus.parsing.standard;
import org.nwapw.abacus.exception.TokenizeException; import org.nwapw.abacus.exception.TokenizeException;
import org.nwapw.abacus.lexing.Lexer; import org.nwapw.abacus.lexing.Lexer;
import org.nwapw.abacus.lexing.pattern.Match; import org.nwapw.abacus.lexing.Match;
import org.nwapw.abacus.lexing.pattern.Pattern; import org.nwapw.abacus.lexing.pattern.Pattern;
import org.nwapw.abacus.parsing.Tokenizer;
import org.nwapw.abacus.plugin.PluginListener; import org.nwapw.abacus.plugin.PluginListener;
import org.nwapw.abacus.plugin.PluginManager; import org.nwapw.abacus.plugin.PluginManager;
import org.nwapw.abacus.tree.TokenType;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
@@ -20,7 +20,7 @@ public class LexerTokenizer implements Tokenizer<Match<TokenType>>, PluginListen
/** /**
* Comparator used to sort the tokens produced by the lexer. * Comparator used to sort the tokens produced by the lexer.
*/ */
protected static final Comparator<TokenType> TOKEN_SORTER = Comparator.comparingInt(e -> e.priority); protected static final Comparator<TokenType> TOKEN_SORTER = (o1, o2) -> o1.priority - o2.priority;
/** /**
* The lexer instance used to turn strings into matches. * The lexer instance used to turn strings into matches.

View File

@@ -1,13 +1,14 @@
package org.nwapw.abacus.parsing; package org.nwapw.abacus.parsing.standard;
import org.nwapw.abacus.exception.ParseException; import org.nwapw.abacus.exception.ParseException;
import org.nwapw.abacus.function.Operator; import org.nwapw.abacus.function.Operator;
import org.nwapw.abacus.function.OperatorAssociativity; import org.nwapw.abacus.function.OperatorAssociativity;
import org.nwapw.abacus.function.OperatorType; import org.nwapw.abacus.function.OperatorType;
import org.nwapw.abacus.lexing.pattern.Match; import org.nwapw.abacus.lexing.Match;
import org.nwapw.abacus.parsing.Parser;
import org.nwapw.abacus.plugin.PluginListener; import org.nwapw.abacus.plugin.PluginListener;
import org.nwapw.abacus.plugin.PluginManager; import org.nwapw.abacus.plugin.PluginManager;
import org.nwapw.abacus.tree.*; import org.nwapw.abacus.tree.nodes.*;
import java.util.*; import java.util.*;
@@ -162,7 +163,7 @@ public class ShuntingYardParser implements Parser<Match<TokenType>>, PluginListe
matches.remove(0); matches.remove(0);
CallNode node; CallNode node;
if (matchType == TokenType.FUNCTION) { if (matchType == TokenType.FUNCTION) {
node = new FunctionNode(functionName, children); node = new NumberFunctionNode(functionName, children);
} else { } else {
node = new TreeValueFunctionNode(functionName, children); node = new TreeValueFunctionNode(functionName, children);
} }

View File

@@ -1,4 +1,4 @@
package org.nwapw.abacus.tree; package org.nwapw.abacus.parsing.standard;
/** /**
* Enum to represent the type of the token that has been matched * Enum to represent the type of the token that has been matched

View File

@@ -1,10 +1,10 @@
package org.nwapw.abacus.plugin; package org.nwapw.abacus.plugin;
import org.nwapw.abacus.number.NumberInterface; import org.nwapw.abacus.number.NumberInterface;
import org.nwapw.abacus.number.promotion.PromotionFunction;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
/** /**
* A class that holds data about a number implementation. * A class that holds data about a number implementation.
@@ -14,7 +14,7 @@ public abstract class NumberImplementation {
/** /**
* The list of paths through which this implementation can be promoted. * The list of paths through which this implementation can be promoted.
*/ */
private Map<String, Function<NumberInterface, NumberInterface>> promotionPaths; private Map<String, PromotionFunction> promotionPaths;
/** /**
* The implementation class for this implementation. * The implementation class for this implementation.
*/ */
@@ -41,7 +41,7 @@ public abstract class NumberImplementation {
* *
* @return the map of documentation paths. * @return the map of documentation paths.
*/ */
public final Map<String, Function<NumberInterface, NumberInterface>> getPromotionPaths() { public final Map<String, PromotionFunction> getPromotionPaths() {
return promotionPaths; return promotionPaths;
} }

View File

@@ -1,6 +1,11 @@
package org.nwapw.abacus.plugin; package org.nwapw.abacus.plugin;
import org.nwapw.abacus.function.*; import org.nwapw.abacus.function.Documentation;
import org.nwapw.abacus.function.DocumentationType;
import org.nwapw.abacus.function.interfaces.NumberFunction;
import org.nwapw.abacus.function.interfaces.NumberOperator;
import org.nwapw.abacus.function.interfaces.TreeValueFunction;
import org.nwapw.abacus.function.interfaces.TreeValueOperator;
import org.nwapw.abacus.number.NumberInterface; import org.nwapw.abacus.number.NumberInterface;
/** /**

View File

@@ -1,7 +1,12 @@
package org.nwapw.abacus.plugin; package org.nwapw.abacus.plugin;
import org.nwapw.abacus.Abacus; import org.nwapw.abacus.Abacus;
import org.nwapw.abacus.function.*; import org.nwapw.abacus.function.Documentation;
import org.nwapw.abacus.function.DocumentationType;
import org.nwapw.abacus.function.interfaces.NumberFunction;
import org.nwapw.abacus.function.interfaces.NumberOperator;
import org.nwapw.abacus.function.interfaces.TreeValueFunction;
import org.nwapw.abacus.function.interfaces.TreeValueOperator;
import org.nwapw.abacus.number.NumberInterface; import org.nwapw.abacus.number.NumberInterface;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;

View File

@@ -1,10 +1,16 @@
package org.nwapw.abacus.plugin.standard; package org.nwapw.abacus.plugin.standard;
import org.jetbrains.annotations.NotNull;
import org.nwapw.abacus.context.MutableEvaluationContext; import org.nwapw.abacus.context.MutableEvaluationContext;
import org.nwapw.abacus.function.*; import org.nwapw.abacus.context.PluginEvaluationContext;
import org.nwapw.abacus.number.NaiveNumber; import org.nwapw.abacus.function.Documentation;
import org.nwapw.abacus.function.DocumentationType;
import org.nwapw.abacus.function.interfaces.NumberFunction;
import org.nwapw.abacus.function.interfaces.NumberOperator;
import org.nwapw.abacus.function.interfaces.TreeValueOperator;
import org.nwapw.abacus.number.NumberInterface; import org.nwapw.abacus.number.NumberInterface;
import org.nwapw.abacus.number.PreciseNumber; import org.nwapw.abacus.number.standard.NaiveNumber;
import org.nwapw.abacus.number.standard.PreciseNumber;
import org.nwapw.abacus.plugin.NumberImplementation; import org.nwapw.abacus.plugin.NumberImplementation;
import org.nwapw.abacus.plugin.Plugin; import org.nwapw.abacus.plugin.Plugin;
import org.nwapw.abacus.plugin.PluginManager; import org.nwapw.abacus.plugin.PluginManager;
@@ -115,12 +121,12 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberFunction FUNCTION_ABS = new NumberFunction() { public static final NumberFunction FUNCTION_ABS = new NumberFunction() {
@Override @Override
public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) { public boolean matchesParams(PluginEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) { public NumberInterface applyInternal(PluginEvaluationContext context, NumberInterface[] params) {
return params[0].multiply(context.getInheritedNumberImplementation().instanceForString(Integer.toString(params[0].signum()))); return params[0].multiply(context.getInheritedNumberImplementation().instanceForString(Integer.toString(params[0].signum())));
} }
}; };
@@ -129,12 +135,12 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberFunction FUNCTION_LN = new NumberFunction() { public static final NumberFunction FUNCTION_LN = new NumberFunction() {
@Override @Override
public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) { public boolean matchesParams(PluginEvaluationContext context, NumberInterface[] params) {
return params.length == 1 && params[0].compareTo(context.getInheritedNumberImplementation().instanceForString("0")) > 0; return params.length == 1 && params[0].compareTo(context.getInheritedNumberImplementation().instanceForString("0")) > 0;
} }
@Override @Override
public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) { public NumberInterface applyInternal(PluginEvaluationContext context, NumberInterface[] params) {
NumberImplementation implementation = context.getInheritedNumberImplementation(); NumberImplementation implementation = context.getInheritedNumberImplementation();
NumberInterface param = params[0]; NumberInterface param = params[0];
NumberInterface one = implementation.instanceForString("1"); NumberInterface one = implementation.instanceForString("1");
@@ -162,10 +168,12 @@ public class StandardPlugin extends Plugin {
/** /**
* Returns the partial sum of the Taylor series for logx (around x=1). * Returns the partial sum of the Taylor series for logx (around x=1).
* Automatically determines the number of terms needed based on the precision of x. * Automatically determines the number of terms needed based on the precision of x.
*
* @param context
* @param x value at which the series is evaluated. 0 < x < 2. (x=2 is convergent but impractical.) * @param x value at which the series is evaluated. 0 < x < 2. (x=2 is convergent but impractical.)
* @return the partial sum. * @return the partial sum.
*/ */
private NumberInterface getLogPartialSum(MutableEvaluationContext context, NumberInterface x) { private NumberInterface getLogPartialSum(PluginEvaluationContext context, NumberInterface x) {
NumberImplementation implementation = context.getInheritedNumberImplementation(); NumberImplementation implementation = context.getInheritedNumberImplementation();
NumberInterface maxError = x.getMaxError(); NumberInterface maxError = x.getMaxError();
x = x.subtract(implementation.instanceForString("1")); //Terms used are for log(x+1). x = x.subtract(implementation.instanceForString("1")); //Terms used are for log(x+1).
@@ -210,12 +218,12 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberFunction FUNCTION_RAND_INT = new NumberFunction() { public static final NumberFunction FUNCTION_RAND_INT = new NumberFunction() {
@Override @Override
public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) { public boolean matchesParams(PluginEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) { public NumberInterface applyInternal(PluginEvaluationContext context, NumberInterface[] params) {
return context.getInheritedNumberImplementation().instanceForString(Long.toString(Math.round(Math.random() * params[0].floor().intValue()))); return context.getInheritedNumberImplementation().instanceForString(Long.toString(Math.round(Math.random() * params[0].floor().intValue())));
} }
}; };
@@ -228,12 +236,12 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberFunction FUNCTION_SQRT = new NumberFunction() { public static final NumberFunction FUNCTION_SQRT = new NumberFunction() {
@Override @Override
public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) { public boolean matchesParams(PluginEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) { public NumberInterface applyInternal(PluginEvaluationContext context, NumberInterface[] params) {
return OP_CARET.apply(context, params[0], context.getInheritedNumberImplementation().instanceForString(".5")); return OP_CARET.apply(context, params[0], context.getInheritedNumberImplementation().instanceForString(".5"));
} }
}; };
@@ -243,12 +251,12 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberFunction FUNCTION_EXP = new NumberFunction() { public static final NumberFunction FUNCTION_EXP = new NumberFunction() {
@Override @Override
public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) { public boolean matchesParams(PluginEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) { public NumberInterface applyInternal(PluginEvaluationContext context, NumberInterface[] params) {
NumberImplementation implementation = context.getInheritedNumberImplementation(); NumberImplementation implementation = context.getInheritedNumberImplementation();
NumberInterface maxError = params[0].getMaxError(); NumberInterface maxError = params[0].getMaxError();
int n = 0; int n = 0;
@@ -281,12 +289,12 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionSin = new NumberFunction() { public final NumberFunction functionSin = new NumberFunction() {
@Override @Override
public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) { public boolean matchesParams(PluginEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) { public NumberInterface applyInternal(PluginEvaluationContext context, NumberInterface[] params) {
NumberImplementation implementation = context.getInheritedNumberImplementation(); NumberImplementation implementation = context.getInheritedNumberImplementation();
NumberInterface pi = piFor(params[0].getClass()); NumberInterface pi = piFor(params[0].getClass());
NumberInterface twoPi = pi.multiply(implementation.instanceForString("2")); NumberInterface twoPi = pi.multiply(implementation.instanceForString("2"));
@@ -306,12 +314,12 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionCos = new NumberFunction() { public final NumberFunction functionCos = new NumberFunction() {
@Override @Override
public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) { public boolean matchesParams(PluginEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) { public NumberInterface applyInternal(PluginEvaluationContext context, NumberInterface[] params) {
return functionSin.apply(context, piFor(params[0].getClass()).divide(context.getInheritedNumberImplementation().instanceForString("2")) return functionSin.apply(context, piFor(params[0].getClass()).divide(context.getInheritedNumberImplementation().instanceForString("2"))
.subtract(params[0])); .subtract(params[0]));
} }
@@ -321,12 +329,12 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionTan = new NumberFunction() { public final NumberFunction functionTan = new NumberFunction() {
@Override @Override
public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) { public boolean matchesParams(PluginEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) { public NumberInterface applyInternal(PluginEvaluationContext context, NumberInterface[] params) {
return functionSin.apply(context, params[0]).divide(functionCos.apply(context, params[0])); return functionSin.apply(context, params[0]).divide(functionCos.apply(context, params[0]));
} }
}; };
@@ -335,12 +343,12 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionSec = new NumberFunction() { public final NumberFunction functionSec = new NumberFunction() {
@Override @Override
public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) { public boolean matchesParams(PluginEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) { public NumberInterface applyInternal(PluginEvaluationContext context, NumberInterface[] params) {
return context.getInheritedNumberImplementation().instanceForString("1").divide(functionCos.apply(context, params[0])); return context.getInheritedNumberImplementation().instanceForString("1").divide(functionCos.apply(context, params[0]));
} }
}; };
@@ -349,12 +357,12 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionCsc = new NumberFunction() { public final NumberFunction functionCsc = new NumberFunction() {
@Override @Override
public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) { public boolean matchesParams(PluginEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) { public NumberInterface applyInternal(PluginEvaluationContext context, NumberInterface[] params) {
return context.getInheritedNumberImplementation().instanceForString("1").divide(functionSin.apply(context, params[0])); return context.getInheritedNumberImplementation().instanceForString("1").divide(functionSin.apply(context, params[0]));
} }
}; };
@@ -363,12 +371,12 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionCot = new NumberFunction() { public final NumberFunction functionCot = new NumberFunction() {
@Override @Override
public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) { public boolean matchesParams(PluginEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) { public NumberInterface applyInternal(PluginEvaluationContext context, NumberInterface[] params) {
return functionCos.apply(context, params[0]).divide(functionSin.apply(context, params[0])); return functionCos.apply(context, params[0]).divide(functionSin.apply(context, params[0]));
} }
}; };
@@ -378,13 +386,13 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionArcsin = new NumberFunction() { public final NumberFunction functionArcsin = new NumberFunction() {
@Override @Override
public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) { public boolean matchesParams(PluginEvaluationContext context, NumberInterface[] params) {
return params.length == 1 return params.length == 1
&& FUNCTION_ABS.apply(context, params[0]).compareTo(context.getInheritedNumberImplementation().instanceForString("1")) <= 0; && FUNCTION_ABS.apply(context, params[0]).compareTo(context.getInheritedNumberImplementation().instanceForString("1")) <= 0;
} }
@Override @Override
public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) { public NumberInterface applyInternal(PluginEvaluationContext context, NumberInterface[] params) {
NumberImplementation implementation = context.getInheritedNumberImplementation(); NumberImplementation implementation = context.getInheritedNumberImplementation();
if (FUNCTION_ABS.apply(context, params[0]).compareTo(implementation.instanceForString(".8")) >= 0) { if (FUNCTION_ABS.apply(context, params[0]).compareTo(implementation.instanceForString(".8")) >= 0) {
NumberInterface[] newParams = {FUNCTION_SQRT.apply(context, implementation.instanceForString("1").subtract(params[0].multiply(params[0])))}; NumberInterface[] newParams = {FUNCTION_SQRT.apply(context, implementation.instanceForString("1").subtract(params[0].multiply(params[0])))};
@@ -412,12 +420,12 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionArccos = new NumberFunction() { public final NumberFunction functionArccos = new NumberFunction() {
@Override @Override
public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) { public boolean matchesParams(PluginEvaluationContext context, NumberInterface[] params) {
return params.length == 1 && FUNCTION_ABS.apply(context, params[0]).compareTo(context.getInheritedNumberImplementation().instanceForString("1")) <= 0; return params.length == 1 && FUNCTION_ABS.apply(context, params[0]).compareTo(context.getInheritedNumberImplementation().instanceForString("1")) <= 0;
} }
@Override @Override
public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) { public NumberInterface applyInternal(PluginEvaluationContext context, NumberInterface[] params) {
return piFor(params[0].getClass()).divide(context.getInheritedNumberImplementation().instanceForString("2")) return piFor(params[0].getClass()).divide(context.getInheritedNumberImplementation().instanceForString("2"))
.subtract(functionArcsin.apply(context, params)); .subtract(functionArcsin.apply(context, params));
} }
@@ -428,12 +436,12 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionArccsc = new NumberFunction() { public final NumberFunction functionArccsc = new NumberFunction() {
@Override @Override
public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) { public boolean matchesParams(PluginEvaluationContext context, NumberInterface[] params) {
return params.length == 1 && FUNCTION_ABS.apply(context, params[0]).compareTo(context.getInheritedNumberImplementation().instanceForString("1")) >= 0; return params.length == 1 && FUNCTION_ABS.apply(context, params[0]).compareTo(context.getInheritedNumberImplementation().instanceForString("1")) >= 0;
} }
@Override @Override
public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) { public NumberInterface applyInternal(PluginEvaluationContext context, NumberInterface[] params) {
NumberInterface[] reciprocalParamArr = {context.getInheritedNumberImplementation().instanceForString("1").divide(params[0])}; NumberInterface[] reciprocalParamArr = {context.getInheritedNumberImplementation().instanceForString("1").divide(params[0])};
return functionArcsin.apply(context, reciprocalParamArr); return functionArcsin.apply(context, reciprocalParamArr);
} }
@@ -444,12 +452,12 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionArcsec = new NumberFunction() { public final NumberFunction functionArcsec = new NumberFunction() {
@Override @Override
public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) { public boolean matchesParams(PluginEvaluationContext context, NumberInterface[] params) {
return params.length == 1 && FUNCTION_ABS.apply(context, params[0]).compareTo(context.getInheritedNumberImplementation().instanceForString("1")) >= 0; return params.length == 1 && FUNCTION_ABS.apply(context, params[0]).compareTo(context.getInheritedNumberImplementation().instanceForString("1")) >= 0;
} }
@Override @Override
public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) { public NumberInterface applyInternal(PluginEvaluationContext context, NumberInterface[] params) {
NumberInterface[] reciprocalParamArr = {context.getInheritedNumberImplementation().instanceForString("1").divide(params[0])}; NumberInterface[] reciprocalParamArr = {context.getInheritedNumberImplementation().instanceForString("1").divide(params[0])};
return functionArccos.apply(context, reciprocalParamArr); return functionArccos.apply(context, reciprocalParamArr);
} }
@@ -460,12 +468,12 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionArctan = new NumberFunction() { public final NumberFunction functionArctan = new NumberFunction() {
@Override @Override
public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) { public boolean matchesParams(PluginEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) { public NumberInterface applyInternal(PluginEvaluationContext context, NumberInterface[] params) {
NumberImplementation implementation = context.getInheritedNumberImplementation(); NumberImplementation implementation = context.getInheritedNumberImplementation();
if (params[0].signum() == -1) { if (params[0].signum() == -1) {
NumberInterface[] negatedParams = {params[0].negate()}; NumberInterface[] negatedParams = {params[0].negate()};
@@ -502,12 +510,12 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionArccot = new NumberFunction() { public final NumberFunction functionArccot = new NumberFunction() {
@Override @Override
public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) { public boolean matchesParams(PluginEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) { public NumberInterface applyInternal(PluginEvaluationContext context, NumberInterface[] params) {
return piFor(params[0].getClass()).divide(context.getInheritedNumberImplementation().instanceForString("2")) return piFor(params[0].getClass()).divide(context.getInheritedNumberImplementation().instanceForString("2"))
.subtract(functionArctan.apply(context, params)); .subtract(functionArctan.apply(context, params));
} }
@@ -546,7 +554,7 @@ public class StandardPlugin extends Plugin {
* @param x where the series is evaluated. * @param x where the series is evaluated.
* @return the value of the series * @return the value of the series
*/ */
private static NumberInterface sinTaylor(MutableEvaluationContext context, NumberInterface x) { private static NumberInterface sinTaylor(PluginEvaluationContext context, NumberInterface x) {
NumberInterface power = x, multiplier = x.multiply(x).negate(), currentTerm, sum = x; NumberInterface power = x, multiplier = x.multiply(x).negate(), currentTerm, sum = x;
NumberInterface maxError = x.getMaxError(); NumberInterface maxError = x.getMaxError();
int n = 1; int n = 1;
@@ -565,7 +573,7 @@ public class StandardPlugin extends Plugin {
* @param phi an angle (in radians). * @param phi an angle (in radians).
* @return theta in [0, 2pi) that differs from phi by a multiple of 2pi. * @return theta in [0, 2pi) that differs from phi by a multiple of 2pi.
*/ */
private static NumberInterface getSmallAngle(MutableEvaluationContext context, NumberInterface phi, NumberInterface pi) { private static NumberInterface getSmallAngle(PluginEvaluationContext context, NumberInterface phi, NumberInterface pi) {
NumberInterface twoPi = pi.multiply(context.getInheritedNumberImplementation().instanceForString("2")); NumberInterface twoPi = pi.multiply(context.getInheritedNumberImplementation().instanceForString("2"));
NumberInterface theta = FUNCTION_ABS.apply(context, phi).subtract(twoPi NumberInterface theta = FUNCTION_ABS.apply(context, phi).subtract(twoPi
.multiply(FUNCTION_ABS.apply(context, phi).divide(twoPi).floor())); //Now theta is in [0, 2pi). .multiply(FUNCTION_ABS.apply(context, phi).divide(twoPi).floor())); //Now theta is in [0, 2pi).

View File

@@ -1,17 +1,15 @@
package org.nwapw.abacus package org.nwapw.abacus
import org.nwapw.abacus.config.Configuration import org.nwapw.abacus.config.Configuration
import org.nwapw.abacus.context.MutableEvaluationContext
import org.nwapw.abacus.context.EvaluationContext import org.nwapw.abacus.context.EvaluationContext
import org.nwapw.abacus.number.PromotionManager import org.nwapw.abacus.context.MutableEvaluationContext
import org.nwapw.abacus.parsing.LexerTokenizer import org.nwapw.abacus.number.promotion.PromotionManager
import org.nwapw.abacus.parsing.ShuntingYardParser
import org.nwapw.abacus.parsing.TreeBuilder import org.nwapw.abacus.parsing.TreeBuilder
import org.nwapw.abacus.parsing.standard.LexerTokenizer
import org.nwapw.abacus.parsing.standard.ShuntingYardParser
import org.nwapw.abacus.plugin.PluginManager import org.nwapw.abacus.plugin.PluginManager
import org.nwapw.abacus.plugin.standard.StandardPlugin import org.nwapw.abacus.plugin.standard.StandardPlugin
import org.nwapw.abacus.tree.EvaluationResult import org.nwapw.abacus.tree.nodes.TreeNode
import org.nwapw.abacus.tree.NumberReducer
import org.nwapw.abacus.tree.TreeNode
/** /**
* Core class to handle all mathematics. * Core class to handle all mathematics.
@@ -48,7 +46,7 @@ class Abacus(val configuration: Configuration) {
/** /**
* The hidden, mutable implementation of the context. * The hidden, mutable implementation of the context.
*/ */
private val mutableContext = MutableEvaluationContext(numberImplementation = StandardPlugin.IMPLEMENTATION_NAIVE) private val mutableContext = MutableEvaluationContext(numberImplementation = StandardPlugin.IMPLEMENTATION_NAIVE, abacus = this)
/** /**
* The base context from which calculations are started. * The base context from which calculations are started.
*/ */
@@ -107,9 +105,8 @@ class Abacus(val configuration: Configuration) {
* @return the evaluation result. * @return the evaluation result.
*/ */
fun evaluateTreeWithContext(tree: TreeNode, context: MutableEvaluationContext): EvaluationResult { fun evaluateTreeWithContext(tree: TreeNode, context: MutableEvaluationContext): EvaluationResult {
val newReducer = NumberReducer(this, context) val evaluationValue = tree.reduce(context)
val evaluationValue = tree.reduce(newReducer) return EvaluationResult(evaluationValue, context)
return EvaluationResult(evaluationValue, newReducer.context)
} }
} }

View File

@@ -1,4 +1,4 @@
package org.nwapw.abacus.tree package org.nwapw.abacus
import org.nwapw.abacus.context.MutableEvaluationContext import org.nwapw.abacus.context.MutableEvaluationContext
import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.number.NumberInterface

View File

@@ -1,9 +1,10 @@
package org.nwapw.abacus.context package org.nwapw.abacus.context
import org.nwapw.abacus.Abacus
import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.number.NumberInterface
import org.nwapw.abacus.plugin.NumberImplementation import org.nwapw.abacus.plugin.NumberImplementation
import org.nwapw.abacus.tree.Reducer import org.nwapw.abacus.tree.Reducer
import org.nwapw.abacus.tree.TreeNode import org.nwapw.abacus.tree.nodes.TreeNode
/** /**
* A context for the reduction of a [org.nwapw.abacus.tree.TreeNode] into a number. * A context for the reduction of a [org.nwapw.abacus.tree.TreeNode] into a number.
@@ -13,11 +14,11 @@ import org.nwapw.abacus.tree.TreeNode
* *
* @property parent the parent of this context. * @property parent the parent of this context.
* @property numberImplementation the implementation for numbers of this context. * @property numberImplementation the implementation for numbers of this context.
* @property reducer the reducer used by this context. * @property abacus the abacus instance used by this reducer.
*/ */
open class EvaluationContext(val parent: EvaluationContext? = null, abstract class EvaluationContext(val parent: EvaluationContext? = null,
open val numberImplementation: NumberImplementation? = null, open val numberImplementation: NumberImplementation? = null,
open val reducer: Reducer<NumberInterface>? = null) { open val abacus: Abacus? = null): Reducer<NumberInterface> {
/** /**
* The map of variables in this context. * The map of variables in this context.
@@ -47,10 +48,10 @@ open class EvaluationContext(val parent: EvaluationContext? = null,
by ChainSearchDelegate { numberImplementation } by ChainSearchDelegate { numberImplementation }
/** /**
* The reducer inherited from this context's parent. * The Abacus instance inherited from this context's parent.
*/ */
val inheritedReducer: Reducer<NumberInterface> val inheritedAbacus: Abacus
by ChainSearchDelegate { reducer } by ChainSearchDelegate { abacus }
/** /**
* The set of all variables in this context and its parents. * The set of all variables in this context and its parents.

View File

@@ -1,23 +1,26 @@
package org.nwapw.abacus.context package org.nwapw.abacus.context
import org.nwapw.abacus.Abacus
import org.nwapw.abacus.exception.NumberReducerException
import org.nwapw.abacus.exception.ReductionException
import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.number.NumberInterface
import org.nwapw.abacus.plugin.NumberImplementation import org.nwapw.abacus.plugin.NumberImplementation
import org.nwapw.abacus.tree.Reducer import org.nwapw.abacus.tree.nodes.*
import org.nwapw.abacus.tree.TreeNode
/** /**
* A reduction context that is mutable. * A reduction context that is mutable.
*
* @param parent the parent of this context. * @param parent the parent of this context.
* @param numberImplementation the number implementation used in this context. * @param numberImplementation the number implementation used in this context.
* @param reducer the reducer used in this context * @param abacus the abacus instance used.
*/ */
class MutableEvaluationContext(parent: EvaluationContext? = null, class MutableEvaluationContext(parent: EvaluationContext? = null,
numberImplementation: NumberImplementation? = null, numberImplementation: NumberImplementation? = null,
reducer: Reducer<NumberInterface>? = null) : abacus: Abacus? = null) :
EvaluationContext(parent, numberImplementation, reducer) { PluginEvaluationContext(parent, numberImplementation, abacus) {
override var numberImplementation: NumberImplementation? = super.numberImplementation override var numberImplementation: NumberImplementation? = super.numberImplementation
override var reducer: Reducer<NumberInterface>? = super.reducer override var abacus: Abacus? = super.abacus
/** /**
* Writes data stored in the [other] context over data stored in this one. * Writes data stored in the [other] context over data stored in this one.
@@ -25,7 +28,6 @@ class MutableEvaluationContext(parent: EvaluationContext? = null,
*/ */
fun apply(other: EvaluationContext) { fun apply(other: EvaluationContext) {
if(other.numberImplementation != null) numberImplementation = other.numberImplementation if(other.numberImplementation != null) numberImplementation = other.numberImplementation
if(other.reducer != null) reducer = other.reducer
for(name in other.variables) { for(name in other.variables) {
setVariable(name, other.getVariable(name) ?: continue) setVariable(name, other.getVariable(name) ?: continue)
} }
@@ -34,36 +36,56 @@ class MutableEvaluationContext(parent: EvaluationContext? = null,
} }
} }
/** override fun reduceNode(treeNode: TreeNode, vararg children: Any): NumberInterface {
* Sets a variable to a certain [value]. val oldNumberImplementation = numberImplementation
* @param name the name of the variable. val abacus = inheritedAbacus
* @param value the value of the variable. val promotionManager = abacus.promotionManager
*/ val toReturn = when(treeNode){
fun setVariable(name: String, value: NumberInterface) { is NumberNode -> {
variableMap[name] = value inheritedNumberImplementation.instanceForString(treeNode.number)
} }
is VariableNode -> {
/** val variable = getVariable(treeNode.variable)
* Set a definition to a certain [value]. if(variable != null) return variable
* @param name the name of the definition. val definition = getDefinition(treeNode.variable)
* @param value the value of the definition. if(definition != null) return definition.reduce(this)
*/ throw NumberReducerException("variable is not defined.")
fun setDefinition(name: String, value: TreeNode) { }
definitionMap[name] = value is NumberUnaryNode -> {
} val child = children[0] as NumberInterface
numberImplementation = abacus.pluginManager.interfaceImplementationFor(child.javaClass)
/** abacus.pluginManager.operatorFor(treeNode.operation)
* Clears the variables defined in this context. .apply(this, child)
*/ }
fun clearVariables(){ is NumberBinaryNode -> {
variableMap.clear() val left = children[0] as NumberInterface
} val right = children[1] as NumberInterface
val promotionResult = promotionManager.promote(left, right)
/** numberImplementation = promotionResult.promotedTo
* Clears the definitions defined in this context. abacus.pluginManager.operatorFor(treeNode.operation).apply(this, *promotionResult.items)
*/ }
fun clearDefinitions(){ is NumberFunctionNode -> {
definitionMap.clear() val promotionResult = promotionManager
.promote(*children.map { it as NumberInterface }.toTypedArray())
numberImplementation = promotionResult.promotedTo
abacus.pluginManager.functionFor(treeNode.callTo).apply(this, *promotionResult.items)
}
is TreeValueUnaryNode -> {
abacus.pluginManager.treeValueOperatorFor(treeNode.operation)
.apply(this, treeNode.applyTo)
}
is TreeValueBinaryNode -> {
abacus.pluginManager.treeValueOperatorFor(treeNode.operation)
.apply(this, treeNode.left, treeNode.right)
}
is TreeValueFunctionNode -> {
abacus.pluginManager.treeValueFunctionFor(treeNode.callTo)
.apply(this, *treeNode.children.toTypedArray())
}
else -> throw ReductionException("unrecognized tree node.")
}
numberImplementation = oldNumberImplementation
return toReturn
} }
} }

View File

@@ -0,0 +1,58 @@
package org.nwapw.abacus.context
import org.nwapw.abacus.Abacus
import org.nwapw.abacus.number.NumberInterface
import org.nwapw.abacus.plugin.NumberImplementation
import org.nwapw.abacus.tree.nodes.TreeNode
/**
* An evaluation context with limited mutability.
*
* An evaluation context that is mutable but in a limited way, that is, not allowing the modifications
* of variables whose changes might cause issues outside of the function. An example of this would be
* the modification of the [numberImplementation], which would cause code paths such as the parsing
* of NumberNodes to produce a different type of number than if the function did not run, whcih is unacceptable.
*
* @param parent the parent of this context.
* @param numberImplementation the number implementation used in this context.
* @param abacus the abacus instance used.
*/
abstract class PluginEvaluationContext(parent: EvaluationContext? = null,
numberImplementation: NumberImplementation? = null,
abacus: Abacus? = null) :
EvaluationContext(parent, numberImplementation, abacus) {
/**
* Sets a variable to a certain [value].
* @param name the name of the variable.
* @param value the value of the variable.
*/
fun setVariable(name: String, value: NumberInterface) {
variableMap[name] = value
}
/**
* Set a definition to a certain [value].
* @param name the name of the definition.
* @param value the value of the definition.
*/
fun setDefinition(name: String, value: TreeNode) {
definitionMap[name] = value
}
/**
* Clears the variables defined in this context.
*/
fun clearVariables(){
variableMap.clear()
}
/**
* Clears the definitions defined in this context.
*/
fun clearDefinitions(){
definitionMap.clear()
}
}

View File

@@ -1,6 +1,7 @@
package org.nwapw.abacus.function.applicable package org.nwapw.abacus.function
import org.nwapw.abacus.context.MutableEvaluationContext import org.nwapw.abacus.context.MutableEvaluationContext
import org.nwapw.abacus.context.PluginEvaluationContext
import org.nwapw.abacus.exception.DomainException import org.nwapw.abacus.exception.DomainException
/** /**
@@ -18,7 +19,7 @@ interface Applicable<in T : Any, out O : Any> {
* @param params the parameter array to verify for compatibility. * @param params the parameter array to verify for compatibility.
* @return whether the array can be used with applyInternal. * @return whether the array can be used with applyInternal.
*/ */
fun matchesParams(context: MutableEvaluationContext, params: Array<out T>): Boolean fun matchesParams(context: PluginEvaluationContext, params: Array<out T>): Boolean
/** /**
* Applies the applicable object to the given parameters, * Applies the applicable object to the given parameters,
@@ -26,7 +27,7 @@ interface Applicable<in T : Any, out O : Any> {
* @param params the parameters to apply to. * @param params the parameters to apply to.
* @return the result of the application. * @return the result of the application.
*/ */
fun applyInternal(context: MutableEvaluationContext, params: Array<out T>): O fun applyInternal(context: PluginEvaluationContext, params: Array<out T>): O
/** /**
* If the parameters can be used with this applicable, returns * If the parameters can be used with this applicable, returns
@@ -35,7 +36,7 @@ interface Applicable<in T : Any, out O : Any> {
* @param params the parameters to apply to. * @param params the parameters to apply to.
* @return the result of the operation, or null if parameters do not match. * @return the result of the operation, or null if parameters do not match.
*/ */
fun apply(context: MutableEvaluationContext, vararg params: T): O { fun apply(context: PluginEvaluationContext, vararg params: T): O {
if (!matchesParams(context, params)) if (!matchesParams(context, params))
throw DomainException("parameters do not match function requirements.") throw DomainException("parameters do not match function requirements.")
return applyInternal(context, params) return applyInternal(context, params)

View File

@@ -1,6 +1,6 @@
package org.nwapw.abacus.function package org.nwapw.abacus.function.interfaces
import org.nwapw.abacus.function.applicable.Applicable import org.nwapw.abacus.function.Applicable
import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.number.NumberInterface
/** /**

View File

@@ -1,6 +1,9 @@
package org.nwapw.abacus.function package org.nwapw.abacus.function.interfaces
import org.nwapw.abacus.function.applicable.Applicable import org.nwapw.abacus.function.Applicable
import org.nwapw.abacus.function.Operator
import org.nwapw.abacus.function.OperatorAssociativity
import org.nwapw.abacus.function.OperatorType
import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.number.NumberInterface
/** /**

View File

@@ -1,8 +1,8 @@
package org.nwapw.abacus.function package org.nwapw.abacus.function.interfaces
import org.nwapw.abacus.function.applicable.Applicable import org.nwapw.abacus.function.Applicable
import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.number.NumberInterface
import org.nwapw.abacus.tree.TreeNode import org.nwapw.abacus.tree.nodes.TreeNode
/** /**
* A function that operates on trees. * A function that operates on trees.

View File

@@ -1,8 +1,11 @@
package org.nwapw.abacus.function package org.nwapw.abacus.function.interfaces
import org.nwapw.abacus.function.applicable.Applicable import org.nwapw.abacus.function.Applicable
import org.nwapw.abacus.function.Operator
import org.nwapw.abacus.function.OperatorAssociativity
import org.nwapw.abacus.function.OperatorType
import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.number.NumberInterface
import org.nwapw.abacus.tree.TreeNode import org.nwapw.abacus.tree.nodes.TreeNode
/** /**
* An operator that operates on trees. * An operator that operates on trees.

View File

@@ -1,6 +1,7 @@
package org.nwapw.abacus.number package org.nwapw.abacus.number
import org.nwapw.abacus.exception.ComputationInterruptedException import org.nwapw.abacus.exception.ComputationInterruptedException
import org.nwapw.abacus.number.range.NumberRangeBuilder
abstract class NumberInterface: Comparable<NumberInterface> { abstract class NumberInterface: Comparable<NumberInterface> {
@@ -220,6 +221,13 @@ abstract class NumberInterface: Comparable<NumberInterface> {
return fractionalPartInternal() return fractionalPartInternal()
} }
/**
* Checks whether the given number is an integer or not.
*
* @return whether the number is an integer or not.
*/
fun isInteger() = fractionalPart().signum() == 0
/** /**
* Returns a NumberRangeBuilder object, which is used to create a range. * Returns a NumberRangeBuilder object, which is used to create a range.
* The reason that this returns a builder and not an actual range is that * The reason that this returns a builder and not an actual range is that

View File

@@ -1,7 +1,8 @@
@file:JvmName("NumberUtils") @file:JvmName("NumberUtils")
package org.nwapw.abacus.number package org.nwapw.abacus.number.promotion
import org.nwapw.abacus.number.NumberInterface
typealias PromotionFunction = java.util.function.Function<NumberInterface, NumberInterface>
typealias PromotionPath = List<PromotionFunction> typealias PromotionPath = List<PromotionFunction>
typealias NumberClass = Class<NumberInterface> typealias NumberClass = Class<NumberInterface>
@@ -12,5 +13,5 @@ typealias NumberClass = Class<NumberInterface>
* @param from the number to start from. * @param from the number to start from.
*/ */
fun PromotionPath.promote(from: NumberInterface): NumberInterface { fun PromotionPath.promote(from: NumberInterface): NumberInterface {
return fold(from, { current, function -> function.apply(current) }) return fold(from, { current, function -> function.promote(current) })
} }

View File

@@ -0,0 +1,20 @@
package org.nwapw.abacus.number.promotion
import org.nwapw.abacus.number.NumberInterface
/**
* Function that is used to promote a number from one type to another.
*
* A promotion function is used in the promotion system as a mean to
* actually "travel" down the promotion path.
*/
interface PromotionFunction {
/**
* Promotes the given [number] into another type.
* @param number the number to promote from.
* @return the new number with the same value.
*/
fun promote(number: NumberInterface): NumberInterface
}

View File

@@ -1,11 +1,11 @@
package org.nwapw.abacus.number package org.nwapw.abacus.number.promotion
import org.nwapw.abacus.Abacus import org.nwapw.abacus.Abacus
import org.nwapw.abacus.exception.PromotionException import org.nwapw.abacus.exception.PromotionException
import org.nwapw.abacus.number.NumberInterface
import org.nwapw.abacus.plugin.NumberImplementation import org.nwapw.abacus.plugin.NumberImplementation
import org.nwapw.abacus.plugin.PluginListener import org.nwapw.abacus.plugin.PluginListener
import org.nwapw.abacus.plugin.PluginManager import org.nwapw.abacus.plugin.PluginManager
import java.util.function.Function
/** /**
* A class that handles promotions based on priority and the * A class that handles promotions based on priority and the
@@ -31,7 +31,11 @@ class PromotionManager(val abacus: Abacus) : PluginListener {
val fromName = abacus.pluginManager.interfaceImplementationNameFor(from.implementation) val fromName = abacus.pluginManager.interfaceImplementationNameFor(from.implementation)
val toName = abacus.pluginManager.interfaceImplementationNameFor(to.implementation) val toName = abacus.pluginManager.interfaceImplementationNameFor(to.implementation)
if(fromName == toName) return listOf(Function { it }) if(fromName == toName) return listOf(object : PromotionFunction {
override fun promote(number: NumberInterface): NumberInterface {
return number
}
})
if(from.promotionPaths.containsKey(toName)) if(from.promotionPaths.containsKey(toName))
return listOf(from.promotionPaths[toName] ?: return null) return listOf(from.promotionPaths[toName] ?: return null)
@@ -51,7 +55,7 @@ class PromotionManager(val abacus: Abacus) : PluginListener {
val implementations = numbers.map { pluginManager.interfaceImplementationFor(it.javaClass) } val implementations = numbers.map { pluginManager.interfaceImplementationFor(it.javaClass) }
val highestPriority = implementations.sortedBy { it.priority }.last() val highestPriority = implementations.sortedBy { it.priority }.last()
return PromotionResult(items = numbers.map { return PromotionResult(items = numbers.map {
if(it.javaClass == highestPriority.implementation) it if (it.javaClass == highestPriority.implementation) it
else computePaths[pluginManager.interfaceImplementationFor(it.javaClass) to highestPriority] else computePaths[pluginManager.interfaceImplementationFor(it.javaClass) to highestPriority]
?.promote(it) ?: throw PromotionException() ?.promote(it) ?: throw PromotionException()
}.toTypedArray(), promotedTo = highestPriority) }.toTypedArray(), promotedTo = highestPriority)

View File

@@ -1,5 +1,6 @@
package org.nwapw.abacus.number package org.nwapw.abacus.number.promotion
import org.nwapw.abacus.number.NumberInterface
import org.nwapw.abacus.plugin.NumberImplementation import org.nwapw.abacus.plugin.NumberImplementation
/** /**

View File

@@ -1,6 +1,7 @@
package org.nwapw.abacus.number package org.nwapw.abacus.number.range
import org.nwapw.abacus.Abacus import org.nwapw.abacus.Abacus
import org.nwapw.abacus.number.NumberInterface
/** /**
* A closed range designed specifically for [NumberInterface] * A closed range designed specifically for [NumberInterface]

View File

@@ -1,6 +1,7 @@
package org.nwapw.abacus.number package org.nwapw.abacus.number.range
import org.nwapw.abacus.Abacus import org.nwapw.abacus.Abacus
import org.nwapw.abacus.number.NumberInterface
/** /**
* A utility class for creating [NumberRange] instances. * A utility class for creating [NumberRange] instances.

View File

@@ -1,6 +1,6 @@
package org.nwapw.abacus.parsing package org.nwapw.abacus.parsing
import org.nwapw.abacus.tree.TreeNode import org.nwapw.abacus.tree.nodes.TreeNode
/** /**
* Converter from tokens into a parse tree. * Converter from tokens into a parse tree.

View File

@@ -1,6 +1,6 @@
package org.nwapw.abacus.parsing package org.nwapw.abacus.parsing
import org.nwapw.abacus.tree.TreeNode import org.nwapw.abacus.tree.nodes.TreeNode
/** /**
* Class to combine a [Tokenizer] and a [Parser] * Class to combine a [Tokenizer] and a [Parser]

View File

@@ -1,9 +1,9 @@
package org.nwapw.abacus.plugin.standard.operator package org.nwapw.abacus.plugin.standard.operator
import org.nwapw.abacus.context.MutableEvaluationContext import org.nwapw.abacus.context.PluginEvaluationContext
import org.nwapw.abacus.function.NumberOperator
import org.nwapw.abacus.function.OperatorAssociativity import org.nwapw.abacus.function.OperatorAssociativity
import org.nwapw.abacus.function.OperatorType import org.nwapw.abacus.function.OperatorType
import org.nwapw.abacus.function.interfaces.NumberOperator
import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.number.NumberInterface
/** /**
@@ -13,9 +13,9 @@ import org.nwapw.abacus.number.NumberInterface
*/ */
class OperatorAdd: NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) { class OperatorAdd: NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) {
override fun matchesParams(context: MutableEvaluationContext, params: Array<out NumberInterface>) = override fun matchesParams(context: PluginEvaluationContext, params: Array<out NumberInterface>) =
params.size == 2 params.size == 2
override fun applyInternal(context: MutableEvaluationContext, params: Array<out NumberInterface>) = override fun applyInternal(context: PluginEvaluationContext, params: Array<out NumberInterface>) =
params[0] + params[1] params[0] + params[1]
} }

View File

@@ -1,9 +1,9 @@
package org.nwapw.abacus.plugin.standard.operator package org.nwapw.abacus.plugin.standard.operator
import org.nwapw.abacus.context.MutableEvaluationContext import org.nwapw.abacus.context.PluginEvaluationContext
import org.nwapw.abacus.function.NumberOperator
import org.nwapw.abacus.function.OperatorAssociativity import org.nwapw.abacus.function.OperatorAssociativity
import org.nwapw.abacus.function.OperatorType import org.nwapw.abacus.function.OperatorType
import org.nwapw.abacus.function.interfaces.NumberOperator
import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.number.NumberInterface
import org.nwapw.abacus.plugin.standard.StandardPlugin.* import org.nwapw.abacus.plugin.standard.StandardPlugin.*
@@ -14,19 +14,19 @@ import org.nwapw.abacus.plugin.standard.StandardPlugin.*
*/ */
class OperatorCaret: NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 2) { class OperatorCaret: NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 2) {
override fun matchesParams(context: MutableEvaluationContext, params: Array<out NumberInterface>) = override fun matchesParams(context: PluginEvaluationContext, params: Array<out NumberInterface>) =
params.size == 2 params.size == 2
&& !(params[0].signum() == 0 && params[1].signum() == 0) && !(params[0].signum() == 0 && params[1].signum() == 0)
&& !(params[0].signum() == -1 && params[1].fractionalPart().signum() != 0) && !(params[0].signum() == -1 && !params[1].isInteger())
override fun applyInternal(context: MutableEvaluationContext, params: Array<out NumberInterface>): NumberInterface { override fun applyInternal(context: PluginEvaluationContext, params: Array<out NumberInterface>): NumberInterface {
val implementation = context.inheritedNumberImplementation val implementation = context.inheritedNumberImplementation
if (params[0].signum() == 0) if (params[0].signum() == 0)
return implementation.instanceForString("0") return implementation.instanceForString("0")
else if (params[1].signum() == 0) else if (params[1].signum() == 0)
return implementation.instanceForString("1") return implementation.instanceForString("1")
//Detect integer bases: //Detect integer bases:
if (params[0].fractionalPart().signum() == 0 if (params[0].isInteger()
&& FUNCTION_ABS.apply(context, params[1]) < implementation.instanceForString(Integer.toString(Integer.MAX_VALUE)) && FUNCTION_ABS.apply(context, params[1]) < implementation.instanceForString(Integer.toString(Integer.MAX_VALUE))
&& FUNCTION_ABS.apply(context, params[1]) >= implementation.instanceForString("1")) { && FUNCTION_ABS.apply(context, params[1]) >= implementation.instanceForString("1")) {
val newParams = arrayOf(params[0], params[1].fractionalPart()) val newParams = arrayOf(params[0], params[1].fractionalPart())

View File

@@ -1,12 +1,12 @@
package org.nwapw.abacus.plugin.standard.operator package org.nwapw.abacus.plugin.standard.operator
import org.nwapw.abacus.context.MutableEvaluationContext import org.nwapw.abacus.context.PluginEvaluationContext
import org.nwapw.abacus.function.OperatorAssociativity import org.nwapw.abacus.function.OperatorAssociativity
import org.nwapw.abacus.function.OperatorType import org.nwapw.abacus.function.OperatorType
import org.nwapw.abacus.function.TreeValueOperator import org.nwapw.abacus.function.interfaces.TreeValueOperator
import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.number.NumberInterface
import org.nwapw.abacus.tree.TreeNode import org.nwapw.abacus.tree.nodes.TreeNode
import org.nwapw.abacus.tree.VariableNode import org.nwapw.abacus.tree.nodes.VariableNode
/** /**
* The definition operator. * The definition operator.
@@ -16,13 +16,13 @@ import org.nwapw.abacus.tree.VariableNode
*/ */
class OperatorDefine: TreeValueOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) { class OperatorDefine: TreeValueOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) {
override fun matchesParams(context: MutableEvaluationContext, params: Array<out TreeNode>) = override fun matchesParams(context: PluginEvaluationContext, params: Array<out TreeNode>) =
params.size == 2 && params[0] is VariableNode params.size == 2 && params[0] is VariableNode
override fun applyInternal(context: MutableEvaluationContext, params: Array<out TreeNode>): NumberInterface { override fun applyInternal(context: PluginEvaluationContext, params: Array<out TreeNode>): NumberInterface {
val assignTo = (params[0] as VariableNode).variable val assignTo = (params[0] as VariableNode).variable
context.setDefinition(assignTo, params[1]) context.setDefinition(assignTo, params[1])
return params[1].reduce(context.inheritedReducer) return params[1].reduce(context)
} }
} }

View File

@@ -1,9 +1,9 @@
package org.nwapw.abacus.plugin.standard.operator package org.nwapw.abacus.plugin.standard.operator
import org.nwapw.abacus.context.MutableEvaluationContext import org.nwapw.abacus.context.PluginEvaluationContext
import org.nwapw.abacus.function.NumberOperator
import org.nwapw.abacus.function.OperatorAssociativity import org.nwapw.abacus.function.OperatorAssociativity
import org.nwapw.abacus.function.OperatorType import org.nwapw.abacus.function.OperatorType
import org.nwapw.abacus.function.interfaces.NumberOperator
import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.number.NumberInterface
/** /**
@@ -13,9 +13,9 @@ import org.nwapw.abacus.number.NumberInterface
*/ */
class OperatorDivide: NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 1) { class OperatorDivide: NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 1) {
override fun matchesParams(context: MutableEvaluationContext, params: Array<out NumberInterface>) = override fun matchesParams(context: PluginEvaluationContext, params: Array<out NumberInterface>) =
params.size == 2 params.size == 2
override fun applyInternal(context: MutableEvaluationContext, params: Array<out NumberInterface>) = override fun applyInternal(context: PluginEvaluationContext, params: Array<out NumberInterface>) =
params[0] / params[1] params[0] / params[1]
} }

View File

@@ -1,9 +1,9 @@
package org.nwapw.abacus.plugin.standard.operator package org.nwapw.abacus.plugin.standard.operator
import org.nwapw.abacus.context.MutableEvaluationContext import org.nwapw.abacus.context.PluginEvaluationContext
import org.nwapw.abacus.function.NumberOperator
import org.nwapw.abacus.function.OperatorAssociativity import org.nwapw.abacus.function.OperatorAssociativity
import org.nwapw.abacus.function.OperatorType import org.nwapw.abacus.function.OperatorType
import org.nwapw.abacus.function.interfaces.NumberOperator
import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.number.NumberInterface
/** /**
@@ -13,12 +13,12 @@ import org.nwapw.abacus.number.NumberInterface
*/ */
class OperatorFactorial: NumberOperator(OperatorAssociativity.LEFT, OperatorType.UNARY_POSTFIX, 0) { class OperatorFactorial: NumberOperator(OperatorAssociativity.LEFT, OperatorType.UNARY_POSTFIX, 0) {
override fun matchesParams(context: MutableEvaluationContext, params: Array<out NumberInterface>) = override fun matchesParams(context: PluginEvaluationContext, params: Array<out NumberInterface>) =
params.size == 1 params.size == 1
&& params[0].fractionalPart().signum() == 0 && params[0].isInteger()
&& params[0].signum() >= 0 && params[0].signum() >= 0
override fun applyInternal(context: MutableEvaluationContext, params: Array<out NumberInterface>): NumberInterface { override fun applyInternal(context: PluginEvaluationContext, params: Array<out NumberInterface>): NumberInterface {
val implementation = context.inheritedNumberImplementation val implementation = context.inheritedNumberImplementation
val one = implementation.instanceForString("1") val one = implementation.instanceForString("1")
if (params[0].signum() == 0) { if (params[0].signum() == 0) {

View File

@@ -1,9 +1,9 @@
package org.nwapw.abacus.plugin.standard.operator package org.nwapw.abacus.plugin.standard.operator
import org.nwapw.abacus.context.MutableEvaluationContext import org.nwapw.abacus.context.PluginEvaluationContext
import org.nwapw.abacus.function.NumberOperator
import org.nwapw.abacus.function.OperatorAssociativity import org.nwapw.abacus.function.OperatorAssociativity
import org.nwapw.abacus.function.OperatorType import org.nwapw.abacus.function.OperatorType
import org.nwapw.abacus.function.interfaces.NumberOperator
import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.number.NumberInterface
/** /**
@@ -13,9 +13,9 @@ import org.nwapw.abacus.number.NumberInterface
*/ */
class OperatorMultiply: NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 1) { class OperatorMultiply: NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 1) {
override fun matchesParams(context: MutableEvaluationContext, params: Array<out NumberInterface>) = override fun matchesParams(context: PluginEvaluationContext, params: Array<out NumberInterface>) =
params.size == 2 params.size == 2
override fun applyInternal(context: MutableEvaluationContext, params: Array<out NumberInterface>) = override fun applyInternal(context: PluginEvaluationContext, params: Array<out NumberInterface>) =
params[0] * params[1] params[0] * params[1]
} }

View File

@@ -1,11 +1,12 @@
package org.nwapw.abacus.plugin.standard.operator package org.nwapw.abacus.plugin.standard.operator
import org.nwapw.abacus.context.MutableEvaluationContext import org.nwapw.abacus.context.PluginEvaluationContext
import org.nwapw.abacus.function.NumberOperator
import org.nwapw.abacus.function.OperatorAssociativity import org.nwapw.abacus.function.OperatorAssociativity
import org.nwapw.abacus.function.OperatorType import org.nwapw.abacus.function.OperatorType
import org.nwapw.abacus.function.interfaces.NumberOperator
import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.number.NumberInterface
import org.nwapw.abacus.plugin.standard.StandardPlugin.* import org.nwapw.abacus.plugin.standard.StandardPlugin.OP_FACTORIAL
import org.nwapw.abacus.plugin.standard.StandardPlugin.OP_NPR
/** /**
* The "N choose R" operator. * The "N choose R" operator.
@@ -15,11 +16,11 @@ import org.nwapw.abacus.plugin.standard.StandardPlugin.*
*/ */
class OperatorNcr: NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 0) { class OperatorNcr: NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 0) {
override fun matchesParams(context: MutableEvaluationContext, params: Array<out NumberInterface>) = override fun matchesParams(context: PluginEvaluationContext, params: Array<out NumberInterface>) =
params.size == 2 && params[0].fractionalPart().signum() == 0 params.size == 2 && params[0].isInteger()
&& params[1].fractionalPart().signum() == 0 && params[1].isInteger()
override fun applyInternal(context: MutableEvaluationContext, params: Array<out NumberInterface>) = override fun applyInternal(context: PluginEvaluationContext, params: Array<out NumberInterface>) =
OP_NPR.apply(context, *params) / OP_FACTORIAL.apply(context, params[1]) OP_NPR.apply(context, *params) / OP_FACTORIAL.apply(context, params[1])
} }

View File

@@ -1,9 +1,9 @@
package org.nwapw.abacus.plugin.standard.operator package org.nwapw.abacus.plugin.standard.operator
import org.nwapw.abacus.context.MutableEvaluationContext import org.nwapw.abacus.context.PluginEvaluationContext
import org.nwapw.abacus.function.NumberOperator
import org.nwapw.abacus.function.OperatorAssociativity import org.nwapw.abacus.function.OperatorAssociativity
import org.nwapw.abacus.function.OperatorType import org.nwapw.abacus.function.OperatorType
import org.nwapw.abacus.function.interfaces.NumberOperator
import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.number.NumberInterface
/** /**
@@ -13,10 +13,10 @@ import org.nwapw.abacus.number.NumberInterface
*/ */
class OperatorNegate: NumberOperator(OperatorAssociativity.LEFT, OperatorType.UNARY_PREFIX, 0) { class OperatorNegate: NumberOperator(OperatorAssociativity.LEFT, OperatorType.UNARY_PREFIX, 0) {
override fun matchesParams(context: MutableEvaluationContext, params: Array<out NumberInterface>) = override fun matchesParams(context: PluginEvaluationContext, params: Array<out NumberInterface>) =
params.size == 1 params.size == 1
override fun applyInternal(context: MutableEvaluationContext, params: Array<out NumberInterface>) = override fun applyInternal(context: PluginEvaluationContext, params: Array<out NumberInterface>) =
-params[0] -params[0]
} }

View File

@@ -1,9 +1,9 @@
package org.nwapw.abacus.plugin.standard.operator package org.nwapw.abacus.plugin.standard.operator
import org.nwapw.abacus.context.MutableEvaluationContext import org.nwapw.abacus.context.PluginEvaluationContext
import org.nwapw.abacus.function.NumberOperator
import org.nwapw.abacus.function.OperatorAssociativity import org.nwapw.abacus.function.OperatorAssociativity
import org.nwapw.abacus.function.OperatorType import org.nwapw.abacus.function.OperatorType
import org.nwapw.abacus.function.interfaces.NumberOperator
import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.number.NumberInterface
/** /**
@@ -14,11 +14,11 @@ import org.nwapw.abacus.number.NumberInterface
*/ */
class OperatorNpr: NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 0) { class OperatorNpr: NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 0) {
override fun matchesParams(context: MutableEvaluationContext, params: Array<out NumberInterface>) = override fun matchesParams(context: PluginEvaluationContext, params: Array<out NumberInterface>) =
params.size == 2 && params[0].fractionalPart().signum() == 0 params.size == 2 && params[0].isInteger()
&& params[1].fractionalPart().signum() == 0 && params[1].isInteger()
override fun applyInternal(context: MutableEvaluationContext, params: Array<out NumberInterface>): NumberInterface { override fun applyInternal(context: PluginEvaluationContext, params: Array<out NumberInterface>): NumberInterface {
val implementation = context.inheritedNumberImplementation val implementation = context.inheritedNumberImplementation
if (params[0] < params[1] || if (params[0] < params[1] ||
params[0].signum() < 0 || params[0].signum() < 0 ||

View File

@@ -1,12 +1,12 @@
package org.nwapw.abacus.plugin.standard.operator package org.nwapw.abacus.plugin.standard.operator
import org.nwapw.abacus.context.MutableEvaluationContext import org.nwapw.abacus.context.PluginEvaluationContext
import org.nwapw.abacus.function.OperatorAssociativity import org.nwapw.abacus.function.OperatorAssociativity
import org.nwapw.abacus.function.OperatorType import org.nwapw.abacus.function.OperatorType
import org.nwapw.abacus.function.TreeValueOperator import org.nwapw.abacus.function.interfaces.TreeValueOperator
import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.number.NumberInterface
import org.nwapw.abacus.tree.TreeNode import org.nwapw.abacus.tree.nodes.TreeNode
import org.nwapw.abacus.tree.VariableNode import org.nwapw.abacus.tree.nodes.VariableNode
/** /**
* The set operator. * The set operator.
@@ -15,12 +15,12 @@ import org.nwapw.abacus.tree.VariableNode
*/ */
class OperatorSet: TreeValueOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) { class OperatorSet: TreeValueOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) {
override fun matchesParams(context: MutableEvaluationContext, params: Array<out TreeNode>) = override fun matchesParams(context: PluginEvaluationContext, params: Array<out TreeNode>) =
params.size == 2 && params[0] is VariableNode params.size == 2 && params[0] is VariableNode
override fun applyInternal(context: MutableEvaluationContext, params: Array<out TreeNode>): NumberInterface { override fun applyInternal(context: PluginEvaluationContext, params: Array<out TreeNode>): NumberInterface {
val assignTo = (params[0] as VariableNode).variable val assignTo = (params[0] as VariableNode).variable
val value = params[1].reduce(context.inheritedReducer) val value = params[1].reduce(context)
context.setVariable(assignTo, value) context.setVariable(assignTo, value)
return value return value
} }

View File

@@ -1,9 +1,9 @@
package org.nwapw.abacus.plugin.standard.operator package org.nwapw.abacus.plugin.standard.operator
import org.nwapw.abacus.context.MutableEvaluationContext import org.nwapw.abacus.context.PluginEvaluationContext
import org.nwapw.abacus.function.NumberOperator
import org.nwapw.abacus.function.OperatorAssociativity import org.nwapw.abacus.function.OperatorAssociativity
import org.nwapw.abacus.function.OperatorType import org.nwapw.abacus.function.OperatorType
import org.nwapw.abacus.function.interfaces.NumberOperator
import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.number.NumberInterface
/** /**
@@ -13,9 +13,9 @@ import org.nwapw.abacus.number.NumberInterface
*/ */
class OperatorSubtract: NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) { class OperatorSubtract: NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) {
override fun matchesParams(context: MutableEvaluationContext, params: Array<out NumberInterface>) = override fun matchesParams(context: PluginEvaluationContext, params: Array<out NumberInterface>) =
params.size == 2 params.size == 2
override fun applyInternal(context: MutableEvaluationContext, params: Array<out NumberInterface>) = override fun applyInternal(context: PluginEvaluationContext, params: Array<out NumberInterface>) =
params[0] - params[1] params[0] - params[1]
} }

View File

@@ -1,65 +0,0 @@
package org.nwapw.abacus.tree
import org.nwapw.abacus.Abacus
import org.nwapw.abacus.context.EvaluationContext
import org.nwapw.abacus.exception.NumberReducerException
import org.nwapw.abacus.exception.ReductionException
import org.nwapw.abacus.number.NumberInterface
class NumberReducer(val abacus: Abacus, context: EvaluationContext) : Reducer<NumberInterface> {
val context = context.mutableSubInstance()
init {
this.context.reducer = this
}
override fun reduceNode(treeNode: TreeNode, vararg children: Any): NumberInterface {
val promotionManager = abacus.promotionManager
return when(treeNode){
is NumberNode -> {
context.inheritedNumberImplementation.instanceForString(treeNode.number)
}
is VariableNode -> {
val variable = context.getVariable(treeNode.variable)
if(variable != null) return variable
val definition = context.getDefinition(treeNode.variable)
if(definition != null) return definition.reduce(this)
throw NumberReducerException("variable is not defined.")
}
is NumberUnaryNode -> {
val child = children[0] as NumberInterface
context.numberImplementation = abacus.pluginManager.interfaceImplementationFor(child.javaClass)
abacus.pluginManager.operatorFor(treeNode.operation)
.apply(context, child)
}
is NumberBinaryNode -> {
val left = children[0] as NumberInterface
val right = children[1] as NumberInterface
val promotionResult = promotionManager.promote(left, right)
context.numberImplementation = promotionResult.promotedTo
abacus.pluginManager.operatorFor(treeNode.operation).apply(context, *promotionResult.items)
}
is FunctionNode -> {
val promotionResult = promotionManager
.promote(*children.map { it as NumberInterface }.toTypedArray())
context.numberImplementation = promotionResult.promotedTo
abacus.pluginManager.functionFor(treeNode.callTo).apply(context, *promotionResult.items)
}
is TreeValueUnaryNode -> {
abacus.pluginManager.treeValueOperatorFor(treeNode.operation)
.apply(context, treeNode.applyTo)
}
is TreeValueBinaryNode -> {
abacus.pluginManager.treeValueOperatorFor(treeNode.operation)
.apply(context, treeNode.left, treeNode.right)
}
is TreeValueFunctionNode -> {
abacus.pluginManager.treeValueFunctionFor(treeNode.callTo)
.apply(context, *treeNode.children.toTypedArray())
}
else -> throw ReductionException("unrecognized tree node.")
}
}
}

View File

@@ -1,5 +1,7 @@
package org.nwapw.abacus.tree package org.nwapw.abacus.tree
import org.nwapw.abacus.tree.nodes.TreeNode
/** /**
* Reducer interface that takes a tree and returns a single value. * Reducer interface that takes a tree and returns a single value.
* *

View File

@@ -1,4 +1,4 @@
package org.nwapw.abacus.tree package org.nwapw.abacus.tree.nodes
/** /**
* A tree node that holds a binary operation. * A tree node that holds a binary operation.

View File

@@ -1,4 +1,4 @@
package org.nwapw.abacus.tree package org.nwapw.abacus.tree.nodes
/** /**
* Represents a more generic function call. * Represents a more generic function call.

View File

@@ -1,4 +1,6 @@
package org.nwapw.abacus.tree package org.nwapw.abacus.tree.nodes
import org.nwapw.abacus.tree.Reducer
/** /**
* A binary operator node that reduces its children. * A binary operator node that reduces its children.

View File

@@ -1,4 +1,6 @@
package org.nwapw.abacus.tree package org.nwapw.abacus.tree.nodes
import org.nwapw.abacus.tree.Reducer
/** /**
* A tree node that holds a function call. * A tree node that holds a function call.
@@ -8,7 +10,7 @@ package org.nwapw.abacus.tree
* *
* @param function the function string. * @param function the function string.
*/ */
class FunctionNode(function: String, children: List<TreeNode>) : CallNode(function, children) { class NumberFunctionNode(function: String, children: List<TreeNode>) : CallNode(function, children) {
override fun <T : Any> reduce(reducer: Reducer<T>): T { override fun <T : Any> reduce(reducer: Reducer<T>): T {
val children = Array<Any>(children.size, { children[it].reduce(reducer) }) val children = Array<Any>(children.size, { children[it].reduce(reducer) })

View File

@@ -1,4 +1,6 @@
package org.nwapw.abacus.tree package org.nwapw.abacus.tree.nodes
import org.nwapw.abacus.tree.Reducer
/** /**
* A tree node that holds a single number value. * A tree node that holds a single number value.

View File

@@ -1,4 +1,6 @@
package org.nwapw.abacus.tree package org.nwapw.abacus.tree.nodes
import org.nwapw.abacus.tree.Reducer
/** /**
* A unary operator node that reduces its children. * A unary operator node that reduces its children.

View File

@@ -1,4 +1,6 @@
package org.nwapw.abacus.tree package org.nwapw.abacus.tree.nodes
import org.nwapw.abacus.tree.Reducer
/** /**
* A tree node. * A tree node.

View File

@@ -1,4 +1,6 @@
package org.nwapw.abacus.tree package org.nwapw.abacus.tree.nodes
import org.nwapw.abacus.tree.Reducer
/** /**
* A tree node that represents a binary tree value operator. * A tree node that represents a binary tree value operator.

View File

@@ -1,4 +1,6 @@
package org.nwapw.abacus.tree package org.nwapw.abacus.tree.nodes
import org.nwapw.abacus.tree.Reducer
/** /**
* A tree node that represents a tree value function call. * A tree node that represents a tree value function call.

View File

@@ -1,4 +1,6 @@
package org.nwapw.abacus.tree package org.nwapw.abacus.tree.nodes
import org.nwapw.abacus.tree.Reducer
/** /**
* A tree node that represents a unary tree value operator. * A tree node that represents a unary tree value operator.

View File

@@ -1,4 +1,4 @@
package org.nwapw.abacus.tree package org.nwapw.abacus.tree.nodes
/** /**
* A tree node that holds a unary operation. * A tree node that holds a unary operation.

View File

@@ -1,4 +1,6 @@
package org.nwapw.abacus.tree package org.nwapw.abacus.tree.nodes
import org.nwapw.abacus.tree.Reducer
/** /**
* A tree node that holds a placeholder variable. * A tree node that holds a placeholder variable.

View File

@@ -8,7 +8,7 @@ import org.nwapw.abacus.config.Configuration;
import org.nwapw.abacus.exception.DomainException; import org.nwapw.abacus.exception.DomainException;
import org.nwapw.abacus.number.NumberInterface; import org.nwapw.abacus.number.NumberInterface;
import org.nwapw.abacus.plugin.standard.StandardPlugin; import org.nwapw.abacus.plugin.standard.StandardPlugin;
import org.nwapw.abacus.tree.TreeNode; import org.nwapw.abacus.tree.nodes.TreeNode;
public class CalculationTests { public class CalculationTests {

View File

@@ -3,7 +3,7 @@ package org.nwapw.abacus.tests;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.nwapw.abacus.lexing.Lexer; import org.nwapw.abacus.lexing.Lexer;
import org.nwapw.abacus.lexing.pattern.Match; import org.nwapw.abacus.lexing.Match;
import java.util.List; import java.util.List;

View File

@@ -5,19 +5,17 @@ import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.nwapw.abacus.Abacus; import org.nwapw.abacus.Abacus;
import org.nwapw.abacus.config.Configuration; import org.nwapw.abacus.config.Configuration;
import org.nwapw.abacus.number.NaiveNumber; import org.nwapw.abacus.number.promotion.PromotionFunction;
import org.nwapw.abacus.number.NumberInterface; import org.nwapw.abacus.number.range.NumberRange;
import org.nwapw.abacus.number.NumberRange; import org.nwapw.abacus.number.standard.NaiveNumber;
import org.nwapw.abacus.number.PreciseNumber; import org.nwapw.abacus.number.standard.PreciseNumber;
import org.nwapw.abacus.plugin.standard.StandardPlugin; import org.nwapw.abacus.plugin.standard.StandardPlugin;
import java.util.function.Function;
public class RangeTests { public class RangeTests {
private static Abacus abacus = new Abacus(new Configuration( "precise", new String[]{})); private static Abacus abacus = new Abacus(new Configuration( "precise", new String[]{}));
private static Function<NumberInterface, NumberInterface> naivePromotion = i -> new NaiveNumber((i.toString())); private static PromotionFunction naivePromotion = i -> new NaiveNumber((i.toString()));
private static Function<NumberInterface, NumberInterface> precisePromotion = i -> new PreciseNumber((i.toString())); private static PromotionFunction precisePromotion = i -> new PreciseNumber((i.toString()));
@BeforeClass @BeforeClass
public static void prepareTests() { public static void prepareTests() {

View File

@@ -1,17 +1,22 @@
package org.nwapw.abacus.tests; package org.nwapw.abacus.tests;
import org.jetbrains.annotations.NotNull;
import org.junit.Assert; import org.junit.Assert;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.nwapw.abacus.Abacus; import org.nwapw.abacus.Abacus;
import org.nwapw.abacus.config.Configuration; import org.nwapw.abacus.config.Configuration;
import org.nwapw.abacus.context.MutableEvaluationContext; import org.nwapw.abacus.context.MutableEvaluationContext;
import org.nwapw.abacus.function.*; import org.nwapw.abacus.context.PluginEvaluationContext;
import org.nwapw.abacus.lexing.pattern.Match; import org.nwapw.abacus.function.OperatorAssociativity;
import org.nwapw.abacus.function.OperatorType;
import org.nwapw.abacus.function.interfaces.NumberFunction;
import org.nwapw.abacus.function.interfaces.NumberOperator;
import org.nwapw.abacus.lexing.Match;
import org.nwapw.abacus.number.NumberInterface; import org.nwapw.abacus.number.NumberInterface;
import org.nwapw.abacus.parsing.LexerTokenizer; import org.nwapw.abacus.parsing.standard.LexerTokenizer;
import org.nwapw.abacus.parsing.standard.TokenType;
import org.nwapw.abacus.plugin.Plugin; import org.nwapw.abacus.plugin.Plugin;
import org.nwapw.abacus.tree.TokenType;
import java.util.List; import java.util.List;
@@ -21,12 +26,12 @@ public class TokenizerTests {
private static LexerTokenizer lexerTokenizer = new LexerTokenizer(); private static LexerTokenizer lexerTokenizer = new LexerTokenizer();
private static NumberFunction subtractFunction = new NumberFunction() { private static NumberFunction subtractFunction = new NumberFunction() {
@Override @Override
public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) { public boolean matchesParams(PluginEvaluationContext context, NumberInterface[] params) {
return params.length == 2; return params.length == 2;
} }
@Override @Override
public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) { public NumberInterface applyInternal(PluginEvaluationContext context, NumberInterface[] params) {
return params[0].subtract(params[1]); return params[0].subtract(params[1]);
} }
}; };
@@ -37,12 +42,12 @@ public class TokenizerTests {
0) { 0) {
@Override @Override
public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) { public boolean matchesParams(PluginEvaluationContext context, NumberInterface[] params) {
return true; return true;
} }
@Override @Override
public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) { public NumberInterface applyInternal(PluginEvaluationContext context, NumberInterface[] params) {
return subtractFunction.apply(context, params); return subtractFunction.apply(context, params);
} }
}); });
@@ -50,12 +55,12 @@ public class TokenizerTests {
0) { 0) {
@Override @Override
public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) { public boolean matchesParams(PluginEvaluationContext context, NumberInterface[] params) {
return true; return true;
} }
@Override @Override
public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) { public NumberInterface applyInternal(PluginEvaluationContext context, NumberInterface[] params) {
return subtractFunction.apply(context, params); return subtractFunction.apply(context, params);
} }
}); });

View File

@@ -16,12 +16,11 @@ import org.nwapw.abacus.exception.AbacusException;
import org.nwapw.abacus.function.Documentation; import org.nwapw.abacus.function.Documentation;
import org.nwapw.abacus.function.DocumentationType; import org.nwapw.abacus.function.DocumentationType;
import org.nwapw.abacus.number.*; import org.nwapw.abacus.number.*;
import org.nwapw.abacus.plugin.ClassFinder;
import org.nwapw.abacus.plugin.PluginListener; import org.nwapw.abacus.plugin.PluginListener;
import org.nwapw.abacus.plugin.PluginManager; import org.nwapw.abacus.plugin.PluginManager;
import org.nwapw.abacus.plugin.standard.StandardPlugin; import org.nwapw.abacus.plugin.standard.StandardPlugin;
import org.nwapw.abacus.tree.EvaluationResult; import org.nwapw.abacus.EvaluationResult;
import org.nwapw.abacus.tree.TreeNode; import org.nwapw.abacus.tree.nodes.TreeNode;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@@ -360,10 +359,13 @@ public class AbacusController implements PluginListener {
if(documentationInstance == null) if(documentationInstance == null)
documentationInstance = new Documentation(name, "", "", "", DocumentationType.FUNCTION); documentationInstance = new Documentation(name, "", "", "", DocumentationType.FUNCTION);
return documentationInstance; return documentationInstance;
}) }).collect(Collectors.toCollection(ArrayList::new)));
.collect(Collectors.toCollection(ArrayList::new))); functionList.addAll(manager.getAllTreeValueFunctions().stream().map(name -> {
functionList.addAll(manager.getAllTreeValueFunctions().stream().map(name -> pluginManager.documentationFor(name, DocumentationType.TREE_VALUE_FUNCTION)) Documentation documentationInstance = pluginManager.documentationFor(name, DocumentationType.TREE_VALUE_FUNCTION);
.collect(Collectors.toCollection(ArrayList::new))); if(documentationInstance == null)
documentationInstance = new Documentation(name, "", "", "", DocumentationType.TREE_VALUE_FUNCTION);
return documentationInstance;
}).collect(Collectors.toCollection(ArrayList::new)));
functionList.sort(Comparator.comparing(Documentation::getCodeName)); functionList.sort(Comparator.comparing(Documentation::getCodeName));
} }

View File

@@ -1,4 +1,4 @@
package org.nwapw.abacus.plugin; package org.nwapw.abacus.fx;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;