diff --git a/src/org/nwapw/abacus/Abacus.java b/src/org/nwapw/abacus/Abacus.java index 6397157..08f4ba5 100644 --- a/src/org/nwapw/abacus/Abacus.java +++ b/src/org/nwapw/abacus/Abacus.java @@ -25,6 +25,7 @@ public class Abacus { manager.addInstantiated(new StandardPlugin(manager)); mainUi = new Window(manager); mainUi.setVisible(true); + manager.load(); } public static void main(String[] args){ diff --git a/src/org/nwapw/abacus/function/Operator.java b/src/org/nwapw/abacus/function/Operator.java index 18d1555..bd12495 100644 --- a/src/org/nwapw/abacus/function/Operator.java +++ b/src/org/nwapw/abacus/function/Operator.java @@ -1,25 +1,55 @@ package org.nwapw.abacus.function; +/** + * A class that represents a single infix operator. + */ public abstract class Operator { + /** + * The associativity of the operator. + */ private OperatorAssociativity associativity; + /** + * The precedence of the operator. + */ private int precedence; + /** + * The function that is called by this operator. + */ private Function function; + /** + * Creates a new operator with the given parameters. + * @param associativity the associativity of the operator. + * @param precedence the precedence of the operator. + * @param function the function that the operator calls. + */ public Operator(OperatorAssociativity associativity, int precedence, Function function){ this.associativity = associativity; this.precedence = precedence; this.function = function; } + /** + * Gets the operator's associativity. + * @return the associativity. + */ public OperatorAssociativity getAssociativity() { return associativity; } + /** + * Gets the operator's precedence. + * @return the precedence. + */ public int getPrecedence() { return precedence; } + /** + * Gets the operator's function. + * @return the function. + */ public Function getFunction() { return function; } diff --git a/src/org/nwapw/abacus/lexing/Lexer.java b/src/org/nwapw/abacus/lexing/Lexer.java index 0da217e..213330a 100644 --- a/src/org/nwapw/abacus/lexing/Lexer.java +++ b/src/org/nwapw/abacus/lexing/Lexer.java @@ -14,10 +14,25 @@ import java.util.*; */ public class Lexer { + /** + * An entry that represents a pattern that has been registered with the lexer. + * @param the type used to identify the pattern. + */ private static class PatternEntry{ + /** + * The name of the entry. + */ public String name; + /** + * The id of the entry. + */ public T id; + /** + * Creates a new pattern entry with the given name and id. + * @param name the name of the pattern entry. + * @param id the id of the pattern entry. + */ public PatternEntry(String name, T id){ this.name = name; this.id = id; diff --git a/src/org/nwapw/abacus/tree/TreeBuilder.java b/src/org/nwapw/abacus/tree/TreeBuilder.java index d0560e1..de1a8ee 100644 --- a/src/org/nwapw/abacus/tree/TreeBuilder.java +++ b/src/org/nwapw/abacus/tree/TreeBuilder.java @@ -3,14 +3,25 @@ package org.nwapw.abacus.tree; import org.nwapw.abacus.function.OperatorAssociativity; import org.nwapw.abacus.lexing.Lexer; import org.nwapw.abacus.lexing.pattern.Match; -import org.nwapw.abacus.plugin.PluginManager; import java.util.*; +/** + * The builder responsible for turning strings into trees. + */ public class TreeBuilder { + /** + * The lexer used to get the input tokens. + */ private Lexer lexer; + /** + * The map of operator precedences. + */ private HashMap precedenceMap; + /** + * The map of operator associativity. + */ private HashMap associativityMap; /** @@ -18,6 +29,9 @@ public class TreeBuilder { */ protected static Comparator tokenSorter = Comparator.comparingInt(e -> e.priority); + /** + * Creates a new TreeBuilder. + */ public TreeBuilder(){ lexer = new Lexer(){{ register(",", TokenType.COMMA); @@ -29,6 +43,26 @@ public class TreeBuilder { associativityMap = new HashMap<>(); } + /** + * Registers a function with the TreeBuilder. + * @param function the function to register. + */ + public void registerFunction(String function){ + lexer.register(function, TokenType.FUNCTION); + } + + /** + * Registers an operator with the TreeBuilder. + * @param operator the operator to register. + * @param precedence the precedence of the operator. + * @param associativity the associativity of the operator. + */ + public void registerOperator(String operator, int precedence, OperatorAssociativity associativity){ + lexer.register(operator, TokenType.OP); + precedenceMap.put(operator, precedence); + associativityMap.put(operator, associativity); + } + /** * Tokenizes a string, converting it into matches * @param string the string to tokenize. @@ -86,7 +120,9 @@ public class TreeBuilder { } } while(!tokenStack.empty()){ - if(!(tokenStack.peek().getType() == TokenType.OP)) return null; + Match match = tokenStack.peek(); + TokenType matchType = match.getType(); + if(!(matchType == TokenType.OP || matchType == TokenType.FUNCTION)) return null; output.add(tokenStack.pop()); } return output; diff --git a/src/org/nwapw/abacus/tree/TreeNode.java b/src/org/nwapw/abacus/tree/TreeNode.java index a3cae09..50d8991 100644 --- a/src/org/nwapw/abacus/tree/TreeNode.java +++ b/src/org/nwapw/abacus/tree/TreeNode.java @@ -11,6 +11,12 @@ import java.util.*; */ public abstract class TreeNode { + /** + * The function that reduces a tree to a single vale. + * @param reducer the reducer used to reduce the tree. + * @param the type the reducer produces. + * @return the result of the reduction, or null on error. + */ public abstract T reduce(Reducer reducer); } diff --git a/src/org/nwapw/abacus/window/Window.java b/src/org/nwapw/abacus/window/Window.java index e419820..a682e22 100644 --- a/src/org/nwapw/abacus/window/Window.java +++ b/src/org/nwapw/abacus/window/Window.java @@ -1,6 +1,8 @@ package org.nwapw.abacus.window; +import org.nwapw.abacus.function.Operator; import org.nwapw.abacus.number.NumberInterface; +import org.nwapw.abacus.plugin.PluginListener; import org.nwapw.abacus.plugin.PluginManager; import org.nwapw.abacus.tree.NumberReducer; import org.nwapw.abacus.tree.TreeBuilder; @@ -16,7 +18,7 @@ import java.awt.event.MouseEvent; /** * The main UI window for the calculator. */ -public class Window extends JFrame { +public class Window extends JFrame implements PluginListener { private static final String CALC_STRING = "Calculate"; private static final String SYNTAX_ERR_STRING = "Syntax Error"; @@ -128,7 +130,7 @@ public class Window extends JFrame { * Action listener that causes the input to be evaluated. */ private ActionListener evaluateListener = (event) -> { - TreeBuilder builder = new TreeBuilder(); + if(builder == null) return; TreeNode parsedExpression = builder.fromString(inputField.getText()); if(parsedExpression == null){ lastOutputArea.setText(SYNTAX_ERR_STRING); @@ -162,6 +164,7 @@ public class Window extends JFrame { public Window(PluginManager manager){ this(); this.manager = manager; + manager.addListener(this); reducer = new NumberReducer(manager); } @@ -257,4 +260,21 @@ public class Window extends JFrame { } }); } + + @Override + public void onLoad(PluginManager manager) { + builder = new TreeBuilder(); + for(String function : manager.getAllFunctions()){ + builder.registerFunction(function); + } + for(String operator : manager.getAllOperators()){ + Operator operatorObject = manager.operatorFor(operator); + builder.registerOperator(operator, operatorObject.getPrecedence(), operatorObject.getAssociativity()); + } + } + + @Override + public void onUnload(PluginManager manager) { + builder = null; + } }