diff options
Diffstat (limited to 'dice-lang/src/bjc/dicelang/DiceLangEngine.java')
| -rw-r--r-- | dice-lang/src/bjc/dicelang/DiceLangEngine.java | 695 |
1 files changed, 0 insertions, 695 deletions
diff --git a/dice-lang/src/bjc/dicelang/DiceLangEngine.java b/dice-lang/src/bjc/dicelang/DiceLangEngine.java deleted file mode 100644 index 71e5ee8..0000000 --- a/dice-lang/src/bjc/dicelang/DiceLangEngine.java +++ /dev/null @@ -1,695 +0,0 @@ -package bjc.dicelang; - -import static bjc.dicelang.Errors.ErrorKey.EK_ENG_NOCLOSING; -import static bjc.dicelang.Errors.ErrorKey.EK_ENG_NOOPENING; -import static bjc.dicelang.Token.Type.CBRACE; -import static bjc.dicelang.Token.Type.CBRACKET; -import static bjc.dicelang.Token.Type.CPAREN; -import static bjc.dicelang.Token.Type.OBRACE; -import static bjc.dicelang.Token.Type.OBRACKET; -import static bjc.dicelang.Token.Type.OPAREN; - -import java.util.Deque; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.logging.Logger; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import bjc.dicelang.scl.StreamEngine; -import bjc.utils.data.ITree; -import bjc.utils.funcdata.FunctionalList; -import bjc.utils.funcdata.FunctionalMap; -import bjc.utils.funcdata.FunctionalStringTokenizer; -import bjc.utils.funcdata.IList; -import bjc.utils.funcdata.IMap; -import bjc.utils.funcutils.ListUtils; -import bjc.utils.parserutils.TokenUtils; -import bjc.utils.parserutils.splitter.ConfigurableTokenSplitter; - -/** - * Implements the orchestration necessary for processing DiceLang commands. - * - * @author Ben Culkin - */ -public class DiceLangEngine { - /* Logger. */ - private static final Logger LOG = Logger.getLogger(DiceLangEngine.class.getName()); - - /* - * The random fields that are package private instead of private-private - * are for the benefit of the tweaker, so that it can mess around with - * them. - */ - - /* Split tokens around operators with regex */ - ConfigurableTokenSplitter opExpander; - - /* ID for generation. */ - int nextLiteral; - - /* Debug indicator. */ - public boolean debugMode; - /* Should we do shunting? */ - private boolean postfixMode; - /* Should we reverse the token stream? */ - private boolean prefixMode; - /* Should we do step-by-step evaluation? */ - private boolean stepEval; - - /* Shunter for token shunting. */ - Shunter shunt; - /* Tokenizer for tokenizing. */ - Tokenizer tokenzer; - /* Parser for tree construction. */ - Parser parsr; - /* Evaluator for evaluating. */ - Evaluator eval; - - /* Tables for various things. */ - /** - * The symbol table. - */ - public final IMap<Integer, String> symTable; - - /* String literal tables */ - private final IMap<Integer, String> stringLits; - private final IMap<String, String> stringLiterals; - - /* Lists of defns. */ - private final IList<Define> lineDefns; - private final IList<Define> tokenDefns; - - /* Are defns currently sorted by priority? */ - private boolean defnsSorted; - - /* Stream engine for processing streams. */ - StreamEngine streamEng; - - /** - * Create a new DiceLang engine. - */ - public DiceLangEngine() { - /* Initialize defns. */ - lineDefns = new FunctionalList<>(); - tokenDefns = new FunctionalList<>(); - defnsSorted = true; - - /* Initialize tables. */ - symTable = new FunctionalMap<>(); - stringLits = new FunctionalMap<>(); - stringLiterals = new FunctionalMap<>(); - - /* Initialize operator expander. */ - opExpander = new ConfigurableTokenSplitter(true); - opExpander.addMultiDelimiters("(", ")"); - opExpander.addMultiDelimiters("[", "]"); - opExpander.addMultiDelimiters("{", "}"); - opExpander.addSimpleDelimiters(":="); - opExpander.addSimpleDelimiters("=>"); - opExpander.addSimpleDelimiters("//"); - opExpander.addSimpleDelimiters(".+."); - opExpander.addSimpleDelimiters(".*."); - opExpander.addSimpleDelimiters("+"); - opExpander.addSimpleDelimiters("-"); - opExpander.addSimpleDelimiters("*"); - opExpander.addSimpleDelimiters("/"); - opExpander.compile(); - - /* Initialize literal IDs */ - nextLiteral = 1; - - /* Initial mode settings. */ - debugMode = true; - postfixMode = false; - prefixMode = false; - stepEval = false; - - /* Create components. */ - shunt = new Shunter(); - parsr = new Parser(); - - streamEng = new StreamEngine(this); - tokenzer = new Tokenizer(this); - eval = new Evaluator(this); - } - - /** Sort defns by priority. */ - public void sortDefns() { - lineDefns.sort(null); - tokenDefns.sort(null); - - defnsSorted = true; - } - - /** - * Add a defn that's applied to lines. - * - * @param dfn - * The defn to add. - */ - public void addLineDefine(final Define dfn) { - lineDefns.add(dfn); - - defnsSorted = false; - } - - /** - * Add a defn that's applied to tokens. - * - * @param dfn - * The defn to add. - */ - public void addTokenDefine(final Define dfn) { - tokenDefns.add(dfn); - - defnsSorted = false; - } - - /** - * Toggle debug mode. - * - * @return The current state of debug mode. - */ - public boolean toggleDebug() { - debugMode = !debugMode; - - return debugMode; - } - - /** - * Toggle postfix mode. - * - * @return The current state of postfix mode. - */ - public boolean togglePostfix() { - postfixMode = !postfixMode; - - return postfixMode; - } - - /** - * Toggle prefix mode. - * - * @return The current state of prefix mode - */ - public boolean togglePrefix() { - prefixMode = !prefixMode; - - return prefixMode; - } - - /** - * Toggle step-eval mode - * - * @return The current state of step-eval mode - */ - public boolean toggleStepEval() { - stepEval = !stepEval; - - return stepEval; - } - - /* Matches double-angle bracketed strings. */ - private final Pattern nonExpandPattern = - Pattern.compile("<<([^\\>]*(?:\\>(?:[^\\>])*)*)>>"); - - /** - * Run a command to completion. - * - * @param command - * The command to run - * - * @return Whether or not the command ran successfully - */ - public boolean runCommand(final String command) { - /* Preprocess the command into tokens */ - /* @NOTE - * Instead of strings, this should maybe use a RawToken - * class or something. - */ - final IList<String> preprocessedTokens = preprocessCommand(command); - - if (preprocessedTokens == null) { - return false; - } - - /* Lex the string tokens into token-tokens */ - final IList<Token> lexedTokens = lexTokens(preprocessedTokens); - - if (lexedTokens == null) { - return false; - } - - /* Parse the tokens into an AST forest */ - final IList<ITree<Node>> astForest = new FunctionalList<>(); - final boolean succ = Parser.parseTokens(lexedTokens, astForest); - - if (!succ) { - return false; - } - - /* Evaluate the AST forest */ - evaluateForest(astForest); - return true; - } - - /* Lex string tokens into token-tokens */ - private IList<Token> lexTokens(final IList<String> preprocessedTokens) { - final IList<Token> lexedTokens = new FunctionalList<>(); - - for (final String token : preprocessedTokens) { - String newTok = token; - - /* Apply token defns */ - for (final Define dfn : tokenDefns.toIterable()) { - /* @NOTE - * What happens with a define that produces - * multiple tokens from one token? - */ - newTok = dfn.apply(newTok); - } - - /* Lex the token */ - final Token tk = tokenzer.lexToken(token, stringLiterals); - - if (debugMode) { - LOG.finer(String.format("lexed token: %s\n", tk)); - } - - if (tk == null) { - /* Ignore blank tokens */ - continue; - } else if (tk == Token.NIL_TOKEN) { - /* Fail on bad tokens */ - return null; - } else { - lexedTokens.add(tk); - } - } - - if (debugMode) { - String msg = String.format("\tCommand after tokenization: %s\n", lexedTokens.toString()); - LOG.fine(msg); - System.out.print(msg); - } - - /* Preshunt preshunt-marked groups of tokens */ - IList<Token> shuntedTokens = lexedTokens; - final IList<Token> preparedTokens = new FunctionalList<>(); - - boolean succ = removePreshuntTokens(lexedTokens, preparedTokens); - - if (!succ) { - return null; - } - - if (debugMode && !postfixMode) { - String msg = String.format("\tCommand after pre-shunter removal: %s\n", - preparedTokens.toString()); - LOG.fine(msg); - System.out.print(msg); - } - - /* Only shunt if we're not in a special mode. */ - if (!postfixMode && !prefixMode) { - /* Shunt the tokens */ - shuntedTokens = new FunctionalList<>(); - succ = shunt.shuntTokens(preparedTokens, shuntedTokens); - - if (!succ) { - return null; - } - } else if (prefixMode) { - /* Reverse directional tokens */ - /* - * @NOTE - * Merge these two operations into one iteration - * over the list? - */ - preparedTokens.reverse(); - shuntedTokens = preparedTokens.map(this::reverseToken); - } - - if (debugMode && !postfixMode) { - String msg = String.format("\tCommand after shunting: %s\n", shuntedTokens.toString()); - LOG.fine(msg); - System.out.print(msg); - } - - /* Expand token groups */ - final IList<Token> readyTokens = shuntedTokens.flatMap(tk -> { - if (tk.type == Token.Type.TOKGROUP || - tk.type == Token.Type.TAGOP || - tk.type == Token.Type.TAGOPR ) { - LOG.finer(String.format("Expanding token group to: %s\n", tk.tokenValues.toString())); - return tk.tokenValues; - } else { - return new FunctionalList<>(tk); - } - }); - - if (debugMode && !postfixMode) { - String msg = String.format("\tCommand after re-preshunting: %s\n", - readyTokens.toString()); - LOG.fine(msg); - System.out.print(msg); - } - - return readyTokens; - } - - /* - * Reverse orientation-sensitive tokens. - * - * These are things like (, {, and [ - */ - private Token reverseToken(final Token tk) { - switch (tk.type) { - case OBRACE: - return new Token(CBRACE, tk.intValue); - case OPAREN: - return new Token(CPAREN, tk.intValue); - case OBRACKET: - return new Token(CBRACKET, tk.intValue); - case CBRACE: - return new Token(OBRACE, tk.intValue); - case CPAREN: - return new Token(OPAREN, tk.intValue); - case CBRACKET: - return new Token(OBRACKET, tk.intValue); - default: - return tk; - } - } - - /* Preprocess a command into a list of string tokens. */ - private IList<String> preprocessCommand(final String command) { - /* Sort the defines if they aren't sorted */ - if (!defnsSorted) { - sortDefns(); - } - - /* Run the tokens through the stream engine */ - final IList<String> streamToks = new FunctionalList<>(); - final boolean succ = streamEng.doStreams(command.split(" "), - streamToks); - - if (!succ) { - return null; - } - - String newComm = ListUtils.collapseTokens(streamToks, " "); - - if (debugMode) { - String msg = String.format("\tCommand after stream commands: %s\n", newComm); - LOG.fine(msg); - System.out.print(msg); - } - - /* Apply line defns */ - for (final Define dfn : lineDefns.toIterable()) { - newComm = dfn.apply(newComm); - } - - if (debugMode) { - String msg = String.format("\tCommand after line defines: %s\n", newComm); - LOG.fine(msg); - System.out.print(msg); - } - - /* Remove string literals. */ - final List<String> destringedParts = TokenUtils.removeDQuotedStrings(newComm); - final StringBuffer destringedCommand = new StringBuffer(); - - for (final String part : destringedParts) { - /* Handle string literals */ - if (part.startsWith("\"") && part.endsWith("\"")) { - /* Get the actual string. */ - final String litName = "stringLiteral" + nextLiteral; - final String litVal = part.substring(1, part.length() - 1); - - /* - * Insert the string with its escape sequences - * interpreted. - */ - final String descVal = TokenUtils.descapeString(litVal); - stringLiterals.put(litName, descVal); - - if (debugMode) - LOG.finer(String.format("Replaced string literal '%s' with literal no. %d", - descVal, nextLiteral)); - - nextLiteral += 1; - - /* Place a ref. to the string in the command */ - destringedCommand.append(" " + litName + " "); - } else { - destringedCommand.append(part); - } - } - - if (debugMode) { - String msg = String.format("\tCommand after destringing: %s\n", destringedCommand); - LOG.fine(msg); - System.out.print(msg); - - /* Print the string table if it exists. */ - if (stringLiterals.size() > 0) { - System.out.println("\tString literals in table"); - - stringLiterals.forEach((key, val) -> { - System.out.printf("\t\tName: (%s)\tValue: (%s)\n", key, val); - }); - } - } - - /* Split the command into tokens */ - final String strang = destringedCommand.toString(); - IList<String> tokens = FunctionalStringTokenizer.fromString(strang).toList(); - - /* Temporarily remove non-expanding tokens */ - final IMap<String, String> nonExpandedTokens = new FunctionalMap<>(); - tokens = tokens.map(tk -> { - final Matcher nonExpandMatcher = nonExpandPattern.matcher(tk); - - if (nonExpandMatcher.matches()) { - final String tkName = "nonExpandToken" + nextLiteral++; - nonExpandedTokens.put(tkName, nonExpandMatcher.group(1)); - - LOG.finer(String.format("Pulled non-expander '%s' to '%s'", nonExpandMatcher.group(1), - tkName)); - return tkName; - } - - return tk; - }); - - if (debugMode) { - String msg = String.format("\tCommand after removal of non-expanders: %s\n", - tokens.toString()); - LOG.fine(msg); - System.out.print(msg); - } - - /* Expand tokens */ - IList<String> fullyExpandedTokens = tokens.flatMap(opExpander::split); - - if (debugMode) { - String msg = String.format("\tCommand after token expansion: %s\n", - fullyExpandedTokens.toString()); - LOG.fine(msg); - System.out.print(msg); - } - - /* Reinsert non-expanded tokens */ - fullyExpandedTokens = fullyExpandedTokens.map(tk -> { - if (tk.startsWith("nonExpandToken")) return nonExpandedTokens.get(tk); - - return tk; - }); - - if (debugMode) { - String msg = String.format("\tCommand after non-expander reinsertion: %s\n", - fullyExpandedTokens.toString()); - LOG.fine(msg); - System.out.print(msg); - } - - return fullyExpandedTokens; - } - - /* Evaluate a forest of AST nodes. */ - private void evaluateForest(final IList<ITree<Node>> astForest) { - int treeNo = 1; - - for (final ITree<Node> ast : astForest) { - if (debugMode) { - System.out.printf("\t\tTree %d in forest:\n%s\n", treeNo, ast.toString()); - } - - if (debugMode && stepEval) { - /* - * @NOTE - * This is broken until stepwise top-down - * tree transforms are fixed. - */ - int step = 1; - - /* Evaluate it step by step */ - for (final Iterator<ITree<Node>> itr = eval.stepDebug(ast); itr.hasNext();) { - final ITree<Node> nodeStep = itr.next(); - - System.out.printf("\t\tStep %d: Node is %s", step, nodeStep); - - /* Don't evaluate null steps */ - if (nodeStep == null) { - System.out.println(); - - step += 1; - continue; - } - - /* Print out details for results */ - if (nodeStep.getHead().type == Node.Type.RESULT) { - final EvaluatorResult res = nodeStep.getHead().resultVal; - - System.out.printf(" (result is %s", res); - - if (res.type == EvaluatorResult.Type.DICE) { - System.out.printf(" (sample roll %s)", res.diceVal.value()); - } - - if (res.origVal != null) { - System.out.printf(" (original tree is %s)", res.origVal); - } - - System.out.printf(")"); - } - - /* Advance a step */ - System.out.println(); - step += 1; - } - } else { - /* Evaluate it normally */ - final EvaluatorResult res = eval.evaluate(ast); - - if (debugMode) { - System.out.printf("\t\tEvaluates to %s", res); - - if (res.type == EvaluatorResult.Type.DICE) { - System.out.println("\t\t (sample roll " + res.diceVal.value() + ")"); - } - } - } - - System.out.println(); - - treeNo += 1; - } - } - - /* Preshunt preshunt-marked groups of tokens. */ - private boolean removePreshuntTokens(final IList<Token> lexedTokens, - final IList<Token> preparedTokens) { - /* Current nesting level of tokens. */ - int curBraceCount = 0; - - /* Data storage. */ - final Deque<IList<Token>> bracedTokens = new LinkedList<>(); - IList<Token> curBracedTokens = new FunctionalList<>(); - - for (final Token tk : lexedTokens) { - if (tk.type == Token.Type.OBRACE && tk.intValue == 2) { - /* Open a preshunt group. */ - curBraceCount += 1; - - if (curBraceCount != 1) { - /* - * Push the old group onto the group - * stack. - */ - bracedTokens.push(curBracedTokens); - } - - curBracedTokens = new FunctionalList<>(); - } else if (tk.type == Token.Type.CBRACE && tk.intValue == 2) { - /* Close a preshunt group. */ - if (curBraceCount == 0) { - /* - * Error if there couldn't have been an - * opening. - */ - Errors.inst.printError(EK_ENG_NOOPENING); - return false; - } - - curBraceCount -= 1; - - final IList<Token> preshuntTokens = new FunctionalList<>(); - - /* Shunt preshunt group. */ - final boolean success = shunt.shuntTokens(curBracedTokens, preshuntTokens); - - if (debugMode) { - System.out.println("\t\tPreshunted " + curBracedTokens + " into " - + preshuntTokens); - } - - if (!success) { - return false; - } - - if (curBraceCount >= 1) { - /* - * Add the preshunt group to the - * previous group. - */ - curBracedTokens = bracedTokens.pop(); - - curBracedTokens.add(new Token(Token.Type.TOKGROUP, preshuntTokens)); - } else { - /* - * Add the preshunt group to the token - * stream. - */ - preparedTokens.add(new Token(Token.Type.TOKGROUP, preshuntTokens)); - } - } else { - /* - * Add the token to the active preshunt group, - * if there is one.. - */ - if (curBraceCount >= 1) { - curBracedTokens.add(tk); - } else { - preparedTokens.add(tk); - } - } - } - - if (curBraceCount > 0) { - /* There was an unclosed group. */ - Errors.inst.printError(EK_ENG_NOCLOSING); - return false; - } - - return true; - } - - /* Get a string literal from the string literal table. */ - String getStringLiteral(final int key) { - return stringLits.get(key); - } - - /* Add a string literal to the string literal table. */ - /* @NOTE - * The string literal table should be abstracted into some kind of - * auto-numbered map thing. - */ - void addStringLiteral(final int key, final String val) { - stringLits.put(key, val); - } -} |
