From 36e0911c6ec27707a74f0b90b1052a16374243ea Mon Sep 17 00:00:00 2001 From: bjculkin Date: Wed, 1 Mar 2017 10:13:41 -0500 Subject: Package reorganization --- dice-lang/src/bjc/dicelang/Define.java | 125 +++++ dice-lang/src/bjc/dicelang/DiceLangConsole.java | 261 ++++++++++ dice-lang/src/bjc/dicelang/DiceLangEngine.java | 551 +++++++++++++++++++++ dice-lang/src/bjc/dicelang/DoubleMatcher.java | 58 +++ dice-lang/src/bjc/dicelang/Errors.java | 245 +++++++++ dice-lang/src/bjc/dicelang/Evaluator.java | 424 ++++++++++++++++ dice-lang/src/bjc/dicelang/EvaluatorResult.java | 97 ++++ dice-lang/src/bjc/dicelang/Node.java | 82 +++ dice-lang/src/bjc/dicelang/Parser.java | 167 +++++++ dice-lang/src/bjc/dicelang/Shunter.java | 258 ++++++++++ dice-lang/src/bjc/dicelang/StreamEngine.java | 118 +++++ dice-lang/src/bjc/dicelang/Token.java | 140 ++++++ dice-lang/src/bjc/dicelang/Tokenizer.java | 154 ++++++ dice-lang/src/bjc/dicelang/dice/CompoundDie.java | 31 ++ .../src/bjc/dicelang/dice/CompoundingDie.java | 63 +++ dice-lang/src/bjc/dicelang/dice/DiceBox.java | 142 ++++++ dice-lang/src/bjc/dicelang/dice/Die.java | 9 + dice-lang/src/bjc/dicelang/dice/DieExpression.java | 30 ++ dice-lang/src/bjc/dicelang/dice/DieList.java | 8 + dice-lang/src/bjc/dicelang/dice/ExplodingDice.java | 70 +++ dice-lang/src/bjc/dicelang/dice/FudgeDie.java | 37 ++ dice-lang/src/bjc/dicelang/dice/MathDie.java | 74 +++ dice-lang/src/bjc/dicelang/dice/ScalarDie.java | 29 ++ dice-lang/src/bjc/dicelang/dice/SimpleDie.java | 60 +++ dice-lang/src/bjc/dicelang/dice/SimpleDieList.java | 48 ++ dice-lang/src/bjc/dicelang/v2/Define.java | 125 ----- dice-lang/src/bjc/dicelang/v2/DiceLangConsole.java | 261 ---------- dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java | 551 --------------------- dice-lang/src/bjc/dicelang/v2/DoubleMatcher.java | 58 --- dice-lang/src/bjc/dicelang/v2/Errors.java | 245 --------- dice-lang/src/bjc/dicelang/v2/Evaluator.java | 424 ---------------- dice-lang/src/bjc/dicelang/v2/EvaluatorResult.java | 97 ---- dice-lang/src/bjc/dicelang/v2/Node.java | 82 --- dice-lang/src/bjc/dicelang/v2/Parser.java | 167 ------- dice-lang/src/bjc/dicelang/v2/Shunter.java | 258 ---------- dice-lang/src/bjc/dicelang/v2/StreamEngine.java | 118 ----- dice-lang/src/bjc/dicelang/v2/Token.java | 140 ------ dice-lang/src/bjc/dicelang/v2/Tokenizer.java | 154 ------ .../src/bjc/dicelang/v2/dice/CompoundDie.java | 31 -- .../src/bjc/dicelang/v2/dice/CompoundingDie.java | 63 --- dice-lang/src/bjc/dicelang/v2/dice/DiceBox.java | 142 ------ dice-lang/src/bjc/dicelang/v2/dice/Die.java | 9 - .../src/bjc/dicelang/v2/dice/DieExpression.java | 30 -- dice-lang/src/bjc/dicelang/v2/dice/DieList.java | 8 - .../src/bjc/dicelang/v2/dice/ExplodingDice.java | 70 --- dice-lang/src/bjc/dicelang/v2/dice/FudgeDie.java | 37 -- dice-lang/src/bjc/dicelang/v2/dice/MathDie.java | 74 --- dice-lang/src/bjc/dicelang/v2/dice/ScalarDie.java | 29 -- dice-lang/src/bjc/dicelang/v2/dice/SimpleDie.java | 60 --- .../src/bjc/dicelang/v2/dice/SimpleDieList.java | 48 -- 50 files changed, 3281 insertions(+), 3281 deletions(-) create mode 100644 dice-lang/src/bjc/dicelang/Define.java create mode 100644 dice-lang/src/bjc/dicelang/DiceLangConsole.java create mode 100644 dice-lang/src/bjc/dicelang/DiceLangEngine.java create mode 100644 dice-lang/src/bjc/dicelang/DoubleMatcher.java create mode 100644 dice-lang/src/bjc/dicelang/Errors.java create mode 100644 dice-lang/src/bjc/dicelang/Evaluator.java create mode 100644 dice-lang/src/bjc/dicelang/EvaluatorResult.java create mode 100644 dice-lang/src/bjc/dicelang/Node.java create mode 100644 dice-lang/src/bjc/dicelang/Parser.java create mode 100644 dice-lang/src/bjc/dicelang/Shunter.java create mode 100644 dice-lang/src/bjc/dicelang/StreamEngine.java create mode 100644 dice-lang/src/bjc/dicelang/Token.java create mode 100644 dice-lang/src/bjc/dicelang/Tokenizer.java create mode 100644 dice-lang/src/bjc/dicelang/dice/CompoundDie.java create mode 100644 dice-lang/src/bjc/dicelang/dice/CompoundingDie.java create mode 100644 dice-lang/src/bjc/dicelang/dice/DiceBox.java create mode 100644 dice-lang/src/bjc/dicelang/dice/Die.java create mode 100644 dice-lang/src/bjc/dicelang/dice/DieExpression.java create mode 100644 dice-lang/src/bjc/dicelang/dice/DieList.java create mode 100644 dice-lang/src/bjc/dicelang/dice/ExplodingDice.java create mode 100644 dice-lang/src/bjc/dicelang/dice/FudgeDie.java create mode 100644 dice-lang/src/bjc/dicelang/dice/MathDie.java create mode 100644 dice-lang/src/bjc/dicelang/dice/ScalarDie.java create mode 100644 dice-lang/src/bjc/dicelang/dice/SimpleDie.java create mode 100644 dice-lang/src/bjc/dicelang/dice/SimpleDieList.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/Define.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/DiceLangConsole.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/DoubleMatcher.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/Errors.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/Evaluator.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/EvaluatorResult.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/Node.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/Parser.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/Shunter.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/StreamEngine.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/Token.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/Tokenizer.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/dice/CompoundDie.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/dice/CompoundingDie.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/dice/DiceBox.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/dice/Die.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/dice/DieExpression.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/dice/DieList.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/dice/ExplodingDice.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/dice/FudgeDie.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/dice/MathDie.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/dice/ScalarDie.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/dice/SimpleDie.java delete mode 100644 dice-lang/src/bjc/dicelang/v2/dice/SimpleDieList.java (limited to 'dice-lang/src') diff --git a/dice-lang/src/bjc/dicelang/Define.java b/dice-lang/src/bjc/dicelang/Define.java new file mode 100644 index 0000000..2967af6 --- /dev/null +++ b/dice-lang/src/bjc/dicelang/Define.java @@ -0,0 +1,125 @@ +package bjc.dicelang; + +import bjc.utils.data.CircularIterator; + +import static bjc.dicelang.Errors.ErrorKey.*; + +import java.util.Iterator; +import java.util.function.UnaryOperator; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +public class Define implements UnaryOperator { + public static enum Type { LINE, TOKEN } + + public static final int MAX_RECURS = 10; + + public final int priority; + public final boolean inError; + + private boolean doRecur; + private boolean subType; + + private Pattern predicate; + private Pattern searcher; + + private Iterator replacers; + private String replacer; + + public Define(int priorty, + boolean isSub, boolean recur, boolean isCircular, + String predicte, String searchr, Iterable replacrs) { + priority = priorty; + doRecur = recur; + subType = isSub; + + if(predicte != null) { + try { + predicate = Pattern.compile(predicte); + } catch (PatternSyntaxException psex) { + Errors.inst.printError(EK_DFN_PREDSYN, psex.getMessage()); + inError = true; + return; + } + } + + try { + searcher = Pattern.compile(searchr); + } catch (PatternSyntaxException psex) { + Errors.inst.printError(EK_DFN_SRCSYN, psex.getMessage()); + inError = true; + return; + } + + inError = false; + + if(subType) { + if(replacrs.iterator().hasNext()) { + replacers = new CircularIterator<>(replacrs, isCircular); + } else { + replacers = null; + } + } else { + Iterator itr = replacrs.iterator(); + + if(itr.hasNext()) replacer = itr.next(); + else replacer = ""; + } + } + + public String apply(String tok) { + if(inError) return tok; + + if(predicate != null) { + if(!predicate.matcher(tok).matches()) { + return tok; + } + } + + String strang = doPass(tok); + + if(doRecur) { + int recurCount = 0; + + if(strang.equals(tok)) { + return strang; + } else { + String oldStrang = strang; + + do { + strang = doPass(tok); + recurCount += 1; + } while(!strang.equals(oldStrang) && recurCount < MAX_RECURS); + + if(recurCount >= MAX_RECURS) { + Errors.inst.printError(EK_DFN_RECUR, Integer.toString(MAX_RECURS), tok, strang); + return strang; + } + } + } + + return strang; + } + + private String doPass(String tok) { + Matcher searcherMatcher = searcher.matcher(tok); + + if(subType) { + StringBuffer sb = new StringBuffer(); + while(searcherMatcher.find()) { + if(replacers == null) { + searcherMatcher.appendReplacement(sb,""); + } else { + String replac = replacers.next(); + searcherMatcher.appendReplacement(sb, replac); + } + } + + searcherMatcher.appendTail(sb); + return sb.toString(); + } else { + return searcherMatcher.replaceAll(replacer); + } + } +} diff --git a/dice-lang/src/bjc/dicelang/DiceLangConsole.java b/dice-lang/src/bjc/dicelang/DiceLangConsole.java new file mode 100644 index 0000000..d9d9288 --- /dev/null +++ b/dice-lang/src/bjc/dicelang/DiceLangConsole.java @@ -0,0 +1,261 @@ +package bjc.dicelang; + +import static bjc.dicelang.Errors.ErrorKey.*; + +import java.io.IOException; +import java.util.List; +import java.util.LinkedList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import jline.ConsoleReader; +import jline.Terminal; + +public class DiceLangConsole { + private int commandNumber; + + private DiceLangEngine eng; + + private ConsoleReader read; + + public DiceLangConsole(String[] args) { + // @TODO do something with the args + commandNumber = 0; + + eng = new DiceLangEngine(); + + Terminal.setupTerminal(); + } + + public void run() { + try { + read = new ConsoleReader(); + } catch(IOException ioex) { + System.out.println("ERROR: Console init failed"); + return; + } + + System.out.println("dice-lang v0.2"); + + String comm = null; + + try { + comm = read.readLine(String.format("(%d) dice-lang> ", commandNumber)); + } catch (IOException ioex) { + System.out.println("ERROR: I/O failed"); + return; + } + + while(!comm.equals("quit") && !comm.equals("exit")) { + if(comm.startsWith("pragma")) { + boolean success = handlePragma(comm.substring(7)); + + if(success) System.out.println("Pragma completed succesfully"); + else System.out.println("Pragma execution failed"); + } else { + System.out.printf("\tRaw command: %s\n", comm); + + boolean success = eng.runCommand(comm); + + if(success) System.out.println("Command completed succesfully"); + else System.out.println("Command execution failed"); + + commandNumber += 1; + } + + try { + comm = read.readLine(String.format("(%d) dice-lang> ", commandNumber)); + } catch (IOException ioex) { + System.out.println("ERROR: I/O failed"); + return; + } + } + } + + private boolean handlePragma(String pragma) { + System.out.println("\tRaw pragma: " + pragma); + + String pragmaName = null; + int firstIndex = pragma.indexOf(' '); + if(firstIndex == -1) { + pragmaName = pragma; + } else { + pragmaName = pragma.substring(0, firstIndex); + } + + switch(pragmaName) { + case "debug": + System.out.println("\tDebug mode is now " + eng.toggleDebug()); + break; + case "postfix": + System.out.println("\tPostfix mode is now " + eng.togglePostfix()); + break; + case "prefix": + System.out.println("\tPrefix mode is now " + eng.togglePrefix()); + break; + case "stepeval": + System.out.println("\tStepeval mode is now" + eng.toggleStepEval()); + break; + case "define": + return defineMode(pragma.substring(7)); + case "help": + return helpMode(pragma.substring(5)); + default: + Errors.inst.printError(EK_CONS_INVPRAG, pragma); + return false; + } + + return true; + } + + private boolean helpMode(String pragma) { + switch(pragma.trim()) { + case "help": + System.out.println("\tGet help on pragmas"); + break; + case "debug": + System.out.println("\tToggle debug mode. (Output stage results)"); + break; + case "postfix": + System.out.println("\tToggle postfix mode. (Don't shunt tokens)"); + break; + case "prefix": + System.out.println("\tToggle prefix mode. (Reverse token order instead of shunting)"); + break; + case "stepeval": + System.out.println("\tToggle stepeval mode. (Print out evaluation progress)"); + break; + case "define": + System.out.println("\tAdd a macro rewrite directive."); + System.out.println("\tdefine ..."); + break; + default: + System.out.println("\tNo help available for pragma " + pragma); + } + + // Help always works + return true; + } + + /* + * Matches slash-delimited strings + * (like /text/ or /text\/text/) + * Uses the "normal* (special normal*)*" pattern style + * recommended in 'Mastering regular expressions' + * Here, the normal is 'anything but a forward or backslash' + * (in regex, thats '[^/\\]') and the special is 'an escaped forward slash' + * (in regex, thats '\\\\/') + * + * Then, we just follow the pattern, escape it for java strings, and + * add the enclosing slashes + */ + private Pattern slashPattern = Pattern.compile("/((?:\\\\.|[^/\\\\])*)/"); + + private boolean defineMode(String defineText) { + int firstIndex = defineText.indexOf(' '); + int secondIndex = defineText.indexOf(' ', firstIndex + 1); + int thirdIndex = defineText.indexOf(' ', secondIndex + 1); + int fourthIndex = defineText.indexOf(' ', thirdIndex + 1); + int fifthIndex = defineText.indexOf(' ', fourthIndex + 1); + int sixthIndex = defineText.indexOf(' ', fifthIndex + 1); + + if(firstIndex == -1) { + Errors.inst.printError(EK_CONS_INVDEFINE, "(no priority)"); + return false; + } else if(secondIndex == -1) { + Errors.inst.printError(EK_CONS_INVDEFINE, "(no define type)"); + return false; + } else if(thirdIndex == -1) { + Errors.inst.printError(EK_CONS_INVDEFINE, "(no recursion type)"); + return false; + } else if(fourthIndex == -1) { + Errors.inst.printError(EK_CONS_INVDEFINE, "(no guard type)"); + return false; + } else if(fifthIndex == -1) { + Errors.inst.printError(EK_CONS_INVDEFINE, "(no circularity)"); + return false; + } else if(sixthIndex == -1) { + Errors.inst.printError(EK_CONS_INVDEFINE, "(no patterns)"); + return false; + } + + int priority = Integer.parseInt(defineText.substring(0, firstIndex)); + + String defineType = defineText.substring(firstIndex + 1, secondIndex); + + Define.Type type; + boolean subMode = false; + + switch(defineType) { + case "line": + type = Define.Type.LINE; + break; + case "token": + type = Define.Type.TOKEN; + break; + case "subline": + type = Define.Type.LINE; + subMode = true; + break; + case "subtoken": + type = Define.Type.TOKEN; + subMode = true; + break; + default: + Errors.inst.printError(EK_CONS_INVDEFINE, "(unknown type)"); + return false; + } + + boolean doRecur = defineText.substring(secondIndex + 1, thirdIndex) + .equalsIgnoreCase("true"); + boolean hasGuard = defineText.substring(thirdIndex + 1, fourthIndex) + .equalsIgnoreCase("true"); + boolean isCircular = defineText.substring(thirdIndex + 1, fourthIndex) + .equalsIgnoreCase("true"); + + String pats = defineText.substring(fifthIndex + 1).trim(); + Matcher patMatcher = slashPattern.matcher(pats); + + String guardPattern = null; + + if(hasGuard) { + if(!patMatcher.find()) { + Errors.inst.printError(EK_CONS_INVDEFINE, "(no guard pattern)"); + return false; + } + + guardPattern = patMatcher.group(1); + } + + if(!patMatcher.find()) { + Errors.inst.printError(EK_CONS_INVDEFINE, "(no search pattern)"); + return false; + } + + String searchPattern = patMatcher.group(1); + List replacePatterns = new LinkedList<>(); + + while(patMatcher.find()) { + replacePatterns.add(patMatcher.group(1)); + } + + Define dfn = new Define(priority, subMode, doRecur, isCircular, + guardPattern, searchPattern, replacePatterns); + + if(dfn.inError) return false; + + if(type == Define.Type.LINE) { + eng.addLineDefine(dfn); + } else { + eng.addTokenDefine(dfn); + } + + return true; + } + + public static void main(String[] args) { + DiceLangConsole console = new DiceLangConsole(args); + + console.run(); + } +} diff --git a/dice-lang/src/bjc/dicelang/DiceLangEngine.java b/dice-lang/src/bjc/dicelang/DiceLangEngine.java new file mode 100644 index 0000000..195c98a --- /dev/null +++ b/dice-lang/src/bjc/dicelang/DiceLangEngine.java @@ -0,0 +1,551 @@ +package bjc.dicelang; + +import bjc.utils.data.IPair; +import bjc.utils.data.ITree; +import bjc.utils.data.Pair; +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 static bjc.dicelang.Errors.ErrorKey.*; +import static bjc.dicelang.Token.Type.*; + +import java.util.Comparator; +import java.util.Deque; +import java.util.Iterator; +import java.util.List; +import java.util.LinkedList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class DiceLangEngine { + // Input rules for processing tokens + private List> opExpansionList; + private List> deaffixationList; + + // ID for generation + private int nextLiteral; + + // Debug indicator + private 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 postfixing + private Shunter shunt; + // Tokenizer for tokenizing + private Tokenizer tokenzer; + // Parser for tree construction + private Parser parsr; + // Evaluator for evaluating + private Evaluator eval; + + // Tables for symbols + public final IMap symTable; + public final IMap stringLits; + + + // Lists for preprocessing + private IList lineDefns; + private IList tokenDefns; + + // Are defns sorted by priority + private boolean defnsSorted; + + // Stream engine for processing streams + private StreamEngine streamEng; + + public DiceLangEngine() { + lineDefns = new FunctionalList<>(); + tokenDefns = new FunctionalList<>(); + defnsSorted = true; + + symTable = new FunctionalMap<>(); + stringLits = new FunctionalMap<>(); + + opExpansionList = new LinkedList<>(); + + opExpansionList.add(new Pair<>("+", "\\+")); + opExpansionList.add(new Pair<>("-", "-")); + opExpansionList.add(new Pair<>("*", "\\*")); + opExpansionList.add(new Pair<>("//", "//")); + opExpansionList.add(new Pair<>("/", "/")); + opExpansionList.add(new Pair<>(":=", ":=")); + opExpansionList.add(new Pair<>("=>", "=>")); + opExpansionList.add(new Pair<>(",", ",")); + + deaffixationList = new LinkedList<>(); + + deaffixationList.add(new Pair<>("(", "\\(")); + deaffixationList.add(new Pair<>(")", "\\)")); + deaffixationList.add(new Pair<>("[", "\\[")); + deaffixationList.add(new Pair<>("]", "\\]")); + deaffixationList.add(new Pair<>("{", "\\{")); + deaffixationList.add(new Pair<>("}", "}")); + + nextLiteral = 1; + + debugMode = true; + postfixMode = false; + prefixMode = false; + stepEval = false; + + streamEng = new StreamEngine(this); + shunt = new Shunter(); + tokenzer = new Tokenizer(this); + parsr = new Parser(); + eval = new Evaluator(this); + } + + public void sortDefns() { + Comparator defnCmp = (dfn1, dfn2) -> dfn1.priority - dfn2.priority; + + lineDefns.sort(defnCmp); + tokenDefns.sort(defnCmp); + + defnsSorted = true; + } + + public void addLineDefine(Define dfn) { + lineDefns.add(dfn); + + defnsSorted = false; + } + + public void addTokenDefine(Define dfn) { + tokenDefns.add(dfn); + + defnsSorted = false; + } + + public boolean toggleDebug() { + debugMode = !debugMode; + + return debugMode; + } + + public boolean togglePostfix() { + postfixMode = !postfixMode; + + return postfixMode; + } + + public boolean togglePrefix() { + prefixMode = !prefixMode; + + return prefixMode; + } + + public boolean toggleStepEval() { + stepEval = !stepEval; + + return stepEval; + } + + /* + * Matches quote-delimited strings + * (like "text" or "text\"text") + * Uses the "normal* (special normal*)*" pattern style + * recommended in 'Mastering regular expressions' + * Here, the normal is 'anything but a forward or backslash' + * (in regex, thats '[^\""]') and the special is 'an escaped forward slash' + * (in regex, thats '\\"') + * + * Then, we just follow the pattern, escape it for java strings, and + * add the enclosing quotes + */ + private Pattern quotePattern = Pattern.compile("\"([^\\\"]*(?:\\\"(?:[^\\\"])*)*)\""); + + // Similiar to the above, but using angle brackets instead of quotes + private Pattern nonExpandPattern = Pattern.compile("<<([^\\>]*(?:\\>(?:[^\\>])*)*)>>"); + + public boolean runCommand(String command) { + // Sort the defines if they aren't sorted + if(!defnsSorted) sortDefns(); + + IList streamToks = new FunctionalList<>(); + boolean success = streamEng.doStreams(command.split(" "), streamToks); + if(!success) return false; + + String newComm = ListUtils.collapseTokens(streamToks, " "); + + if(debugMode) + System.out.println("\tCommand after stream commands: " + newComm); + + for(Define dfn : lineDefns.toIterable()) { + newComm = dfn.apply(newComm); + } + + if(debugMode) + System.out.println("\tCommand after line defines: " + newComm); + + IMap stringLiterals = new FunctionalMap<>(); + + Matcher quoteMatcher = quotePattern.matcher(newComm); + StringBuffer destringedCommand = new StringBuffer(); + + while(quoteMatcher.find()) { + String stringLit = quoteMatcher.group(1); + + String litName = "stringLiteral" + nextLiteral++; + stringLiterals.put(litName, stringLit); + + quoteMatcher.appendReplacement(destringedCommand, " " + litName + " "); + } + + quoteMatcher.appendTail(destringedCommand); + + // Split the command into tokens + IList tokens = FunctionalStringTokenizer + .fromString(destringedCommand.toString()).toList(); + + if(debugMode) { + System.out.println("\tCommand after destringing: " + destringedCommand); + + if(stringLiterals.getSize() > 0) { + System.out.println("\tString literals in table"); + + stringLiterals.forEach((key, val) -> { + System.out.printf("\t\tName: (%s)\tValue: (%s)\n", key, val); + }); + } + } + + IMap nonExpandedTokens = new FunctionalMap<>(); + + tokens = tokens.map(tk -> { + Matcher nonExpandMatcher = nonExpandPattern.matcher(tk); + + if(nonExpandMatcher.matches()) { + String tkName = "nonExpandToken" + nextLiteral++; + nonExpandedTokens.put(tkName, nonExpandMatcher.group(1)); + + return tkName; + } else { + return tk; + } + }); + + System.out.println("\tCommand after removal of non-expanders: " + tokens.toString()); + + IList semiExpandedTokens = deaffixTokens(tokens, deaffixationList); + IList fullyExpandedTokens = deaffixTokens(semiExpandedTokens, opExpansionList); + + System.out.println("\tCommand after token expansion: " + fullyExpandedTokens.toString()); + + fullyExpandedTokens = fullyExpandedTokens.map(tk -> { + if(tk.startsWith("nonExpandToken")) { + return nonExpandedTokens.get(tk); + } else { + return tk; + } + }); + + if(debugMode) + System.out.printf("\tCommand after non-expander reinsertion: " + + fullyExpandedTokens.toString() + "\n"); + + + IList lexedTokens = new FunctionalList<>(); + + for(String token : fullyExpandedTokens) { + String newTok = token; + + for(Define dfn : tokenDefns.toIterable()) { + newTok = dfn.apply(newTok); + } + + Token tk = tokenzer.lexToken(token, stringLiterals); + + if(tk == null) continue; + else if(tk == Token.NIL_TOKEN) return false; + else lexedTokens.add(tk); + } + + if(debugMode) + System.out.printf("\tCommand after tokenization: %s\n", lexedTokens.toString()); + + IList shuntedTokens = lexedTokens; + + IList preparedTokens = new FunctionalList<>(); + boolean sc = removePreshuntTokens(lexedTokens, preparedTokens); + + if(!sc) return false; + + if(debugMode && !postfixMode) + System.out.printf("\tCommand after pre-shunter removal: %s\n", preparedTokens.toString()); + + if(!postfixMode && !prefixMode) { + shuntedTokens = new FunctionalList<>(); + success = shunt.shuntTokens(preparedTokens, shuntedTokens); + if(!success) return false; + } else if(prefixMode) { + preparedTokens.reverse(); + shuntedTokens = preparedTokens.map(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; + } + }); + } + + if(debugMode && !postfixMode) + System.out.printf("\tCommand after shunting: %s\n", shuntedTokens.toString()); + + IList readyTokens = shuntedTokens.flatMap(tk -> { + if(tk.type == Token.Type.TOKGROUP) { + return tk.tokenValues; + } else if(tk.type == Token.Type.TAGOP || tk.type == Token.Type.TAGOPR) { + return tk.tokenValues; + } else { + return new FunctionalList<>(tk); + } + }); + + if(debugMode && !postfixMode) + System.out.printf("\tCommand after re-preshunting: %s\n", readyTokens.toString()); + + IList> astForest = new FunctionalList<>(); + success = parsr.parseTokens(readyTokens, astForest); + + if(!success) return false; + + if(debugMode) { + evaluateForest(astForest); + } + + return true; + } + + private void evaluateForest(IList> astForest) { + System.out.println("\tParsed forest of asts"); + int treeNo = 1; + + for(ITree ast : astForest) { + System.out.println("\t\tTree " + treeNo + " in forest:\n" + ast); + + if(stepEval) { + int step = 1; + + for(Iterator> itr = eval.stepDebug(ast); itr.hasNext();){ + ITree nodeStep = itr.next(); + + System.out.printf("\t\tStep %d: Node is %s", step, nodeStep); + + if(nodeStep == null) { + System.out.println(); + + step += 1; + continue; + } + + if(nodeStep.getHead().type == Node.Type.RESULT) { + 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(")"); + } + + + System.out.println(); + step += 1; + } + } else { + EvaluatorResult res = eval.evaluate(ast); + 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; + } + } + + private boolean removePreshuntTokens(IList lexedTokens, IList preparedTokens) { + boolean success; + int curBraceCount = 0; + Deque> bracedTokens = new LinkedList<>(); + IList curBracedTokens = null; + + for(Token tk : lexedTokens) { + if(tk.type == Token.Type.OBRACE && tk.intValue == 2) { + curBraceCount += 1; + + if(curBraceCount != 1) { + bracedTokens.push(curBracedTokens); + } + + curBracedTokens = new FunctionalList<>(); + } else if(tk.type == Token.Type.CBRACE && tk.intValue == 2) { + if(curBraceCount == 0) { + Errors.inst.printError(EK_ENG_NOOPENING); + return false; + } + + curBraceCount -= 1; + + IList preshuntTokens = new FunctionalList<>(); + + success = shunt.shuntTokens(curBracedTokens, preshuntTokens); + + if(debugMode) + System.out.println("\t\tPreshunted " + curBracedTokens + " into " + preshuntTokens); + + if(!success) return false; + + if(curBraceCount >= 1) { + curBracedTokens = bracedTokens.pop(); + + curBracedTokens.add(new Token(Token.Type.TOKGROUP, preshuntTokens)); + } else { + preparedTokens.add(new Token(Token.Type.TOKGROUP, preshuntTokens)); + } + } else { + if(curBraceCount >= 1) { + curBracedTokens.add(tk); + } else { + preparedTokens.add(tk); + } + } + } + + if(curBraceCount > 0) { + Errors.inst.printError(EK_ENG_NOCLOSING); + return false; + } + + return true; + } + + + + private IList deaffixTokens(IList tokens, List> deaffixTokens) { + Deque working = new LinkedList<>(); + + for(String tk : tokens) { + working.add(tk); + } + + for(IPair op : deaffixTokens) { + Deque newWorking = new LinkedList<>(); + + String opRegex = op.getRight(); + + Pattern opRegexPattern = Pattern.compile(opRegex); + Pattern opRegexOnly = Pattern.compile("\\A(?:" + opRegex + ")+\\Z"); + Pattern opRegexStarting = Pattern.compile("\\A" + opRegex); + Pattern opRegexEnding = Pattern.compile(opRegex + "\\Z"); + + for(String tk : working) { + if(opRegexOnly.matcher(tk).matches()) { + // The string contains only the operator + newWorking.add(tk); + } else { + Matcher medianMatcher = opRegexPattern.matcher(tk); + + // Read the first match + boolean found = medianMatcher.find(); + + if(!found) { + newWorking.add(tk); + continue; + } + + Matcher startMatcher = opRegexStarting.matcher(tk); + Matcher endMatcher = opRegexEnding.matcher(tk); + + boolean startsWith = startMatcher.find(); + boolean endsWith = endMatcher.find(); + boolean doSplit = medianMatcher.find(); + + medianMatcher.reset(); + + if(doSplit || (!startsWith && !endsWith)) { + String[] pieces = opRegexPattern.split(tk); + + if(startsWith) { + // Skip the starting operator + medianMatcher.find(); + newWorking.add(tk.substring(0, startMatcher.end())); + } + + for(int i = 0; i < pieces.length; i++) { + String piece = pieces[i]; + + // Find the next operator + boolean didFind = medianMatcher.find(); + + if(piece.equals("")) { + System.out.printf("\tWARNING: Empty token found during operator expansion" + + "of token (%s). Weirdness may happen as a result\n", tk); + continue; + } + + newWorking.add(piece); + + if(didFind) + newWorking.add(tk.substring(medianMatcher.start(), medianMatcher.end())); + } + + if(endsWith) + newWorking.add(tk.substring(endMatcher.start())); + } else if(startsWith && endsWith) { + newWorking.add(tk.substring(0, startMatcher.end())); + newWorking.add(tk.substring(startMatcher.end(), endMatcher.start())); + newWorking.add(tk.substring(endMatcher.start())); + } else if(startsWith) { + newWorking.add(tk.substring(0, startMatcher.end())); + newWorking.add(tk.substring(startMatcher.end())); + } else if(endsWith) { + newWorking.add(tk.substring(0, endMatcher.start())); + newWorking.add(tk.substring(endMatcher.start())); + } else { + newWorking.add(tk); + } + } + + } + + working = newWorking; + } + + IList returned = new FunctionalList<>(); + for(String ent : working) { + returned.add(ent); + } + + return returned; + } +} diff --git a/dice-lang/src/bjc/dicelang/DoubleMatcher.java b/dice-lang/src/bjc/dicelang/DoubleMatcher.java new file mode 100644 index 0000000..75df9c7 --- /dev/null +++ b/dice-lang/src/bjc/dicelang/DoubleMatcher.java @@ -0,0 +1,58 @@ +package bjc.dicelang; + +import java.util.regex.Pattern; + +/** + * Checks if a string would pass Double.parseDouble. + * + * Uses a regex from the javadoc for Double.valueOf() + */ +public class DoubleMatcher { + private static final String Digits = + "(\\p{Digit}+)"; + private static final String HexDigits = + "(\\p{XDigit}+)"; + + // an exponent is 'e' or 'E' followed by an optionally + // signed decimal integer. + private static final String Exp = + "[eE][+-]?" + Digits; + + private static final String fpRegex = + ("[\\x00-\\x20]*" + + // Optional leading "whitespace" + "[+-]?(" + // Optional sign character + "NaN|" + // "NaN" string + "Infinity|" + // "Infinity" string + + // A decimal floating-point string representing a finite positive + // number without a leading sign has at most five basic pieces: + // Digits . Digits ExponentPart FloatTypeSuffix + // + // Since this method allows integer-only strings as input + // in addition to strings of floating-point literals, the + // two sub-patterns below are simplifications of the grammar + // productions from section 3.10.2 of + // The Java™ Language Specification. + + // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt + "((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+ + + // . Digits ExponentPart_opt FloatTypeSuffix_opt + "(\\.("+Digits+")("+Exp+")?)|"+ + + // Hexadecimal strings + "((" + + // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt + "(0[xX]" + HexDigits + "(\\.)?)|" + + + // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt + "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" + + + ")[pP][+-]?" + Digits + "))" + + "[fFdD]?))" + + "[\\x00-\\x20]*");// Optional trailing "whitespace" + + public static final Pattern floatingLiteral = Pattern.compile("\\A" + fpRegex + "\\Z"); + +} diff --git a/dice-lang/src/bjc/dicelang/Errors.java b/dice-lang/src/bjc/dicelang/Errors.java new file mode 100644 index 0000000..e6a825c --- /dev/null +++ b/dice-lang/src/bjc/dicelang/Errors.java @@ -0,0 +1,245 @@ +package bjc.dicelang; + +public class Errors { + public static enum ErrorKey { + // Define Errors + // Incorrect define guard syntax + EK_DFN_PREDSYN, + // Incorrect define search syntax + EK_DFN_SRCSYN, + // Recursive define recursed too many times + EK_DFN_RECUR, + + // Console Errors + // Unknown console pragma + EK_CONS_INVPRAG, + // Improperly formatted define + EK_CONS_INVDEFINE, + + // Language Engine Errors + // Found closing doublebrace w/out opening doublebrace + EK_ENG_NOOPENING, + // Reached end of command w/out balanced doublebraces + EK_ENG_NOCLOSING, + + // Tokenizer Errors + // Found an unexpected grouping token + EK_TOK_UNGROUP, + // Invalid base for a flexadecimal number + EK_TOK_INVBASE, + // Invalid flexadecimal number in a given base + EK_TOK_INVFLEX, + + // Evaluator Errors + // Unknown node type + EK_EVAL_INVNODE, + // Incorrect # of args to binary operator + EK_EVAL_INVBIN, + // Incorrect # of args to unary operator + EK_EVAL_INVUNARY, + // Unknown binary operator + EK_EVAL_UNBIN, + // Unknown unary operator + EK_EVAL_UNUNARY, + // Math on strings doesn't work + EK_EVAL_STRINGMATH, + // Attempted divide by zero + EK_EVAL_DIVZERO, + // Attempted to divide dice + EK_EVAL_DIVDICE, + // Unknown math operator + EK_EVAL_UNMATH, + // Unknown token reference + EK_EVAL_UNTOK, + // Unknown dice operator + EK_EVAL_UNDICE, + // Incorrect type to dice group operator + EK_EVAL_INVDGROUP, + // Incorrect type to other dice operator + EK_EVAL_INVDICE, + // Mismatched types to math operator + EK_EVAL_MISMATH, + + // Parser Error + // Group closing where there couldn't be an opener + EK_PARSE_NOCLOSE, + // Group closing without group opener + EK_PARSE_UNCLOSE, + // Incorrect # of arguments to binary operator + EK_PARSE_BINARY, + // Not enough operands to binary operator + EK_PARSE_UNOPERAND, + // Unrecognized token type + EK_PARSE_INVTOKEN, + + // Shunter Error + // Unary operator expected a operand, but got an operator + EK_SHUNT_NOTADV, + // Unary operator expected an operator, but got an operand + EK_SHUNT_NOTADJ, + // Unary operator expected an operator, but didn't find one + EK_SHUNT_NOOP, + // Asked for opening grouping operator, but couldn't find one + EK_SHUNT_NOGROUP, + // No group for group seperator to attach to + EK_SHUNT_INVSEP, + + // Stream Errors + // Attempted to switch to a non-existant stream + EK_STRM_NONEX, + // Can't delete the last stream + EK_STRM_LAST, + // Unknown stream command + EK_STRM_INVCOM, + + } + + public static enum ErrorMode { + WIZARD, DEV + } + + private ErrorMode mode; + + public void printError(ErrorKey key, String... args) { + switch(mode) { + case WIZARD: + System.out.println("\t? " + key.ordinal()); + break; + case DEV: + devError(key, args); + break; + default: + System.out.println("\tERROR ERROR: Unknown error mode " + mode); + } + } + + private void devError(ErrorKey key, String[] args) { + switch(key) { + case EK_DFN_PREDSYN: + System.out.printf("\tERROR: Incorrect define guard syntax %s\n", args[0]); + break; + case EK_DFN_SRCSYN: + System.out.printf("\tERROR: Incorrect define match syntax %s\n", args[0]); + break; + case EK_DFN_RECUR: + System.out.printf("\tERROR: Recursive define didn't converge after %s iterations." + + " Original string was %s, last iteration was %s\n", + args[0], args[1], args[2]); + break; + case EK_CONS_INVPRAG: + System.out.printf("\tERROR: Unknown pragma %s\n", args[0]); + break; + case EK_CONS_INVDEFINE: + System.out.printf("\tERROR: Improperly formatted define %s\n", args[0]); + break; + case EK_ENG_NOOPENING: + System.out.printf("\tERROR: Encountered closing doublebrace without" + + " matching opening doublebrace\n"); + break; + case EK_ENG_NOCLOSING: + System.out.printf("\tERROR: Reached end of string before closing doublebrace was found\n"); + break; + case EK_TOK_UNGROUP: + System.out.printf("\tERROR: Unrecognized grouping token %s\n", args[0]); + break; + case EK_TOK_INVBASE: + System.out.printf("\tERROR: Invalid flexadecimal base %s\n", args[0]); + break; + case EK_TOK_INVFLEX: + System.out.printf("\tERROR: Invalid flexadecimal number %s in base %s\n", args[0], args[1]); + break; + case EK_EVAL_INVNODE: + System.out.printf("\tERROR: Unknown node in evaluator: %s\n", args[0]); + break; + case EK_EVAL_INVBIN: + System.out.printf("\tERROR: Binary operators take 2 operand, not %s\n" + + "\tProblem node is %s\n", args[0], args[1]); + break; + case EK_EVAL_UNBIN: + System.out.printf("\tERROR: Unknown binary operator %s\n", args[0]); + break; + case EK_EVAL_STRINGMATH: + System.out.printf("\tERROR: Math operators don't work on strings\n"); + break; + case EK_EVAL_DIVZERO: + System.out.printf("\tERROR: Attempted divide by zero\n"); + break; + case EK_EVAL_DIVDICE: + System.out.printf("\tERROR: Dice cannot be divided\n"); + break; + case EK_EVAL_UNMATH: + System.out.printf("\tERROR: Unknown math binary operator: %s\n", args[0]); + break; + case EK_EVAL_UNTOK: + System.out.printf("\tERROR: Unknown token ref %s\n", args[0]); + break; + case EK_EVAL_UNDICE: + System.out.printf("\tERROR: Unknown dice operator %s\n", args[0]); + break; + case EK_EVAL_INVDGROUP: + System.out.printf("\tERROR: Dice group operator expects scalar dice or integers," + + " not %s\n", args[0]); + break; + case EK_EVAL_INVDICE: + System.out.printf("\tERROR: Dice operators expect scalar dice, not %s\n", args[0]); + break; + case EK_EVAL_MISMATH: + System.out.printf("\tERROR: Math operators expect two operands of the same type\n"); + break; + case EK_PARSE_NOCLOSE: + System.out.printf("\tERROR: Group closing with no possible group opener\n"); + break; + case EK_PARSE_UNCLOSE: + System.out.printf("\tERROR: Found group closer without opener: (closing was %s" + + ", expected %s)\n", args[0], args[1]); + break; + case EK_PARSE_BINARY: + System.out.printf("\tERROR: Expected at least two operands\n"); + break; + case EK_PARSE_UNOPERAND: + System.out.printf("\tERROR: Operator %s expected more operands than provided\n", args[0]); + break; + case EK_PARSE_INVTOKEN: + System.out.printf("\tERROR: Unrecognized token type in parsing: %s\n", args[0]); + break; + case EK_SHUNT_NOTADV: + System.out.printf("\tERROR: Unary operator %s is an adjective, not an adverb. It can't be" + + " applied to the operator %s\n", args[0], args[1]); + break; + case EK_SHUNT_NOTADJ: + System.out.printf("\tERROR: Unary operator %s is an adjective, not an adverb. It can't be" + + " applied to the operator %s\n", args[0], args[1]); + break; + case EK_SHUNT_NOOP: + System.out.printf("\tERROR: Unary operator %s is an adverb, but there is no operator" + + " to apply it to\n", args[0]); + break; + case EK_SHUNT_NOGROUP: + System.out.printf("\tERROR: Couldn't find matching grouping %s (expected %s)\n", + args[0], args[1]); + break; + case EK_SHUNT_INVSEP: + System.out.printf("\tERROR: Couldn't find grouper for group seperator to attach to\n"); + break; + case EK_STRM_NONEX: + System.out.printf("\tERROR: Attempted to switch to non-existent stream\n"); + break; + case EK_STRM_LAST: + System.out.printf("\tERROR: Cannot delete last stream\n"); + break; + case EK_STRM_INVCOM: + System.out.printf("\tERROR: Unknown stream control command %s\n", args[0]); + break; + default: + System.out.printf("\tERROR ERROR: Unknown error key %s\n", key); + } + } + + public final static Errors inst; + + static { + inst = new Errors(); + + inst.mode = ErrorMode.DEV; + } +} diff --git a/dice-lang/src/bjc/dicelang/Evaluator.java b/dice-lang/src/bjc/dicelang/Evaluator.java new file mode 100644 index 0000000..7b9bc83 --- /dev/null +++ b/dice-lang/src/bjc/dicelang/Evaluator.java @@ -0,0 +1,424 @@ +package bjc.dicelang; + +import bjc.dicelang.dice.CompoundDie; +import bjc.dicelang.dice.MathDie; +import bjc.dicelang.dice.SimpleDie; +import bjc.dicelang.dice.SimpleDieList; +import bjc.utils.data.ITree; +import bjc.utils.data.SingleIterator; +import bjc.utils.data.Tree; +import bjc.utils.data.TopDownTransformIterator; +import bjc.utils.data.TopDownTransformResult; + +import static bjc.dicelang.Errors.ErrorKey.*; +import static bjc.dicelang.EvaluatorResult.Type.*; + +import java.util.Deque; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.function.Consumer; + +public class Evaluator { + private static enum CoerceSteps { + INTEGER, FLOAT; + } + + private static class Context { + public Consumer>> thunk; + + public boolean isDebug; + } + + private static Node FAIL() { + return new Node(Node.Type.RESULT, new EvaluatorResult(FAILURE)); + } + + private static Node FAIL(ITree orig) { + return new Node(Node.Type.RESULT, new EvaluatorResult(FAILURE, orig)); + } + + private static Node FAIL(Node orig) { + return new Node(Node.Type.RESULT, new EvaluatorResult(FAILURE, orig)); + } + + private static Node FAIL(EvaluatorResult res) { + return new Node(Node.Type.RESULT, new EvaluatorResult(FAILURE, new Node(Node.Type.RESULT, res))); + } + + private DiceLangEngine eng; + + public Evaluator(DiceLangEngine en) { + eng = en; + } + + public EvaluatorResult evaluate(ITree comm) { + Context ctx = new Context(); + + ctx.isDebug = false; + ctx.thunk = (itr) -> { + // Deliberately finish the iterator, but ignore results. It's only for stepwise evaluation + // but we don't know if stepping the iterator causes something to happen + while(itr.hasNext()) itr.next(); + }; + + return comm.topDownTransform(this::pickEvaluationType, + (node) -> this.evaluateNode(node, ctx)).getHead().resultVal; + } + + // @FIXME Something's broken with step evaluation + public Iterator> stepDebug(ITree comm) { + Context ctx = new Context(); + + ctx.isDebug = true; + + return new TopDownTransformIterator<>(this::pickEvaluationType, (node, thnk) -> { + ctx.thunk = thnk; + + return this.evaluateNode(node, ctx); + }, comm); + } + + private TopDownTransformResult pickEvaluationType(Node nd) { + switch(nd.type) { + case UNARYOP: + switch(nd.operatorType) { + case COERCE: + return TopDownTransformResult.RTRANSFORM; + default: + return TopDownTransformResult.PUSHDOWN; + } + default: + return TopDownTransformResult.PUSHDOWN; + } + } + + private ITree evaluateNode(ITree ast, Context ctx) { + switch(ast.getHead().type) { + case UNARYOP: + return evaluateUnaryOp(ast, ctx); + case BINOP: + return evaluateBinaryOp(ast, ctx); + case TOKREF: + return evaluateTokenRef(ast.getHead().tokenVal, ctx); + case ROOT: + return ast.getChild(ast.getChildrenCount() - 1); + case RESULT: + return ast; + default: + Errors.inst.printError(EK_EVAL_INVNODE, ast.getHead().type.toString()); + return new Tree<>(FAIL(ast)); + } + } + + private ITree evaluateUnaryOp(ITree ast, Context ctx) { + switch(ast.getHead().operatorType) { + case COERCE: + if(ast.getChildrenCount() != 1) { + Errors.inst.printError(EK_EVAL_UNUNARY, Integer.toString(ast.getChildrenCount())); + return new Tree<>(FAIL(ast)); + } + + ITree toCoerce = ast.getChild(0); + ITree retVal = new Tree<>(toCoerce.getHead()); + Deque> children = new LinkedList<>(); + + CoerceSteps curLevel = CoerceSteps.INTEGER; + + for(int i = 0; i < toCoerce.getChildrenCount(); i++) { + ITree child = toCoerce.getChild(i); + ITree nChild = null; + + if(ctx.isDebug) { + Iterator> nd = stepDebug(child); + + for(; nd.hasNext(); nChild = nd.next()) { + ctx.thunk.accept(new SingleIterator<>(child)); + } + } else { + nChild = new Tree<>(new Node(Node.Type.RESULT, evaluate(child))); + + if(nChild != null) ctx.thunk.accept(new SingleIterator<>(nChild)); + } + + Node childNode = nChild.getHead(); + EvaluatorResult res = childNode.resultVal; + + if(res.type == FLOAT) curLevel = CoerceSteps.FLOAT; + + children.add(nChild); + } + + for(ITree child : children) { + Node nd = child.getHead(); + EvaluatorResult res = nd.resultVal; + + switch(res.type) { + case INT: + if(curLevel == CoerceSteps.FLOAT) { + nd.resultVal = new EvaluatorResult(FLOAT, (double)res.intVal); + } + default: + // Do nothing + break; + } + + retVal.addChild(child); + } + + return retVal; + default: + Errors.inst.printError(EK_EVAL_INVUNARY, ast.getHead().operatorType.toString()); + return new Tree<>(FAIL(ast)); + } + } + + private ITree evaluateBinaryOp(ITree ast, Context ctx) { + Token.Type binOp = ast.getHead().operatorType; + + if(ast.getChildrenCount() != 2) { + Errors.inst.printError(EK_EVAL_INVBIN, Integer.toString(ast.getChildrenCount()), ast.toString()); + + return new Tree<>(FAIL(ast)); + } + + ITree left = ast.getChild(0); + ITree right = ast.getChild(1); + + switch(binOp) { + case ADD: + case SUBTRACT: + case MULTIPLY: + case DIVIDE: + case IDIVIDE: + return evaluateMathBinary(binOp, + left.getHead().resultVal, right.getHead().resultVal, + ctx); + case DICEGROUP: + case DICECONCAT: + case DICELIST: + return evaluateDiceBinary(binOp, + left.getHead().resultVal, right.getHead().resultVal, + ctx); + default: + Errors.inst.printError(EK_EVAL_UNBIN, binOp.toString()); + return new Tree<>(FAIL(ast)); + } + } + + private ITree evaluateDiceBinary(Token.Type op, + EvaluatorResult left, EvaluatorResult right, Context ctx) { + EvaluatorResult res = null; + + switch(op) { + case DICEGROUP: + if(left.type == DICE && !left.diceVal.isList) { + if(right.type == DICE && !right.diceVal.isList) { + res = new EvaluatorResult(DICE, + new SimpleDie(left.diceVal.scalar, right.diceVal.scalar)); + } else if (right.type == INT) { + res = new EvaluatorResult(DICE, new SimpleDie(left.diceVal.scalar, right.intVal)); + } else { + Errors.inst.printError(EK_EVAL_INVDGROUP, right.type.toString()); + return new Tree<>(FAIL(right)); + } + } else if(left.type == INT) { + if(right.type == DICE && !right.diceVal.isList) { + res = new EvaluatorResult(DICE, new SimpleDie(left.intVal, right.diceVal.scalar)); + } else if (right.type == INT) { + res = new EvaluatorResult(DICE, new SimpleDie(left.intVal, right.intVal)); + } else { + Errors.inst.printError(EK_EVAL_INVDGROUP, right.type.toString()); + return new Tree<>(FAIL(right)); + } + } else { + Errors.inst.printError(EK_EVAL_INVDGROUP, left.type.toString()); + return new Tree<>(FAIL(left)); + } + case DICECONCAT: + if(left.type != DICE || left.diceVal.isList) { + Errors.inst.printError(EK_EVAL_INVDICE, left.type.toString()); + return new Tree<>(FAIL(left)); + } else if(right.type != DICE || right.diceVal.isList) { + Errors.inst.printError(EK_EVAL_INVDICE, right.type.toString()); + return new Tree<>(FAIL(right)); + } else { + res = new EvaluatorResult(DICE, + new CompoundDie(left.diceVal.scalar, right.diceVal.scalar)); + } + break; + case DICELIST: + if(left.type != DICE || left.diceVal.isList) { + Errors.inst.printError(EK_EVAL_INVDICE, left.type.toString()); + return new Tree<>(FAIL(left)); + } else if(right.type != DICE || right.diceVal.isList) { + Errors.inst.printError(EK_EVAL_INVDICE, right.type.toString()); + return new Tree<>(FAIL(right)); + } else { + res = new EvaluatorResult(DICE, + new SimpleDieList(left.diceVal.scalar, right.diceVal.scalar)); + } + break; + default: + Errors.inst.printError(EK_EVAL_UNDICE, op.toString()); + return new Tree<>(FAIL()); + } + + return new Tree<>(new Node(Node.Type.RESULT, res)); + } + + private ITree evaluateMathBinary(Token.Type op, + EvaluatorResult left, EvaluatorResult right, Context ctx) { + if(left.type == STRING || right.type == STRING) { + Errors.inst.printError(EK_EVAL_STRINGMATH); + return new Tree<>(FAIL()); + } else if(left.type == FAILURE || right.type == FAILURE) { + return new Tree<>(FAIL()); + } else if(left.type == INT && right.type != INT) { + Errors.inst.printError(EK_EVAL_MISMATH); + return new Tree<>(FAIL(right)); + } else if(left.type == FLOAT && right.type != FLOAT) { + Errors.inst.printError(EK_EVAL_MISMATH); + return new Tree<>(FAIL(right)); + } else if(left.type == DICE && right.type != DICE) { + Errors.inst.printError(EK_EVAL_MISMATH); + return new Tree<>(FAIL(right)); + } else if(right.type == INT && left.type != INT) { + Errors.inst.printError(EK_EVAL_MISMATH); + return new Tree<>(FAIL(left)); + } else if(right.type == FLOAT && left.type != FLOAT) { + Errors.inst.printError(EK_EVAL_MISMATH); + return new Tree<>(FAIL(left)); + } else if(right.type == DICE && left.type != DICE) { + Errors.inst.printError(EK_EVAL_MISMATH); + return new Tree<>(FAIL(left)); + } + + EvaluatorResult res = null; + + switch(op) { + case ADD: + if(left.type == INT) { + res = new EvaluatorResult(INT, left.intVal + right.intVal); + } else if(left.type == DICE) { + if(left.diceVal.isList) { + Errors.inst.printError(EK_EVAL_INVDICE, left.toString()); + return new Tree<>(FAIL(left)); + } else if(right.diceVal.isList) { + Errors.inst.printError(EK_EVAL_INVDICE, right.toString()); + return new Tree<>(FAIL(right)); + } + + res = new EvaluatorResult(DICE, new MathDie(MathDie.MathOp.ADD, + left.diceVal.scalar, right.diceVal.scalar)); + } else { + res = new EvaluatorResult(FLOAT, left.floatVal + right.floatVal); + } + break; + case SUBTRACT: + if(left.type == INT) { + res = new EvaluatorResult(INT, left.intVal - right.intVal); + } else if(left.type == DICE) { + if(left.diceVal.isList) { + Errors.inst.printError(EK_EVAL_INVDICE, left.toString()); + return new Tree<>(FAIL(left)); + } else if(right.diceVal.isList) { + Errors.inst.printError(EK_EVAL_INVDICE, right.toString()); + return new Tree<>(FAIL(right)); + } + + res = new EvaluatorResult(DICE, new MathDie(MathDie.MathOp.SUBTRACT, + left.diceVal.scalar, right.diceVal.scalar)); + } else { + res = new EvaluatorResult(FLOAT, left.floatVal - right.floatVal); + } + break; + case MULTIPLY: + if(left.type == INT) { + res = new EvaluatorResult(INT, left.intVal * right.intVal); + } else if(left.type == DICE) { + if(left.diceVal.isList) { + Errors.inst.printError(EK_EVAL_INVDICE, left.toString()); + return new Tree<>(FAIL(left)); + } else if(right.diceVal.isList) { + Errors.inst.printError(EK_EVAL_INVDICE, right.toString()); + return new Tree<>(FAIL(right)); + } + + res = new EvaluatorResult(DICE, new MathDie(MathDie.MathOp.MULTIPLY, + left.diceVal.scalar, right.diceVal.scalar)); + } else { + res = new EvaluatorResult(FLOAT, left.floatVal * right.floatVal); + } + break; + case DIVIDE: + if(left.type == INT) { + if(right.intVal == 0) { + Errors.inst.printError(EK_EVAL_DIVZERO); + res = new EvaluatorResult(FAILURE, right); + } else { + res = new EvaluatorResult(FLOAT, left.intVal / right.intVal); + } + } else if(left.type == FLOAT) { + if(right.floatVal == 0) { + Errors.inst.printError(EK_EVAL_DIVZERO); + res = new EvaluatorResult(FAILURE, right); + } else { + res = new EvaluatorResult(FLOAT, left.floatVal / right.floatVal); + } + } else { + Errors.inst.printError(EK_EVAL_DIVDICE); + return new Tree<>(FAIL()); + } + break; + case IDIVIDE: + if(left.type == INT) { + if(right.intVal == 0) { + Errors.inst.printError(EK_EVAL_DIVZERO); + res = new EvaluatorResult(FAILURE, right); + } else { + res = new EvaluatorResult(INT, (int) (left.intVal / right.intVal)); + } + } else if(left.type == FLOAT) { + if(right.floatVal == 0) { + Errors.inst.printError(EK_EVAL_DIVZERO); + res = new EvaluatorResult(FAILURE, right); + } else { + res = new EvaluatorResult(INT, (int) (left.floatVal / right.floatVal)); + } + } else { + Errors.inst.printError(EK_EVAL_DIVDICE); + return new Tree<>(FAIL()); + } + break; + default: + Errors.inst.printError(EK_EVAL_UNMATH, op.toString()); + return new Tree<>(FAIL()); + } + + return new Tree<>(new Node(Node.Type.RESULT, res)); + } + + private ITree evaluateTokenRef(Token tk, Context ctx) { + EvaluatorResult res = null; + + switch(tk.type) { + case INT_LIT: + res = new EvaluatorResult(INT, tk.intValue); + break; + case FLOAT_LIT: + res = new EvaluatorResult(FLOAT, tk.floatValue); + break; + case DICE_LIT: + res = new EvaluatorResult(DICE, tk.diceValue); + break; + case STRING_LIT: + res = new EvaluatorResult(STRING, eng.stringLits.get((int)(tk.intValue))); + break; + default: + Errors.inst.printError(EK_EVAL_UNTOK, tk.type.toString()); + res = new EvaluatorResult(FAILURE); + } + + return new Tree<>(new Node(Node.Type.RESULT, res)); + } +} diff --git a/dice-lang/src/bjc/dicelang/EvaluatorResult.java b/dice-lang/src/bjc/dicelang/EvaluatorResult.java new file mode 100644 index 0000000..ef70d3d --- /dev/null +++ b/dice-lang/src/bjc/dicelang/EvaluatorResult.java @@ -0,0 +1,97 @@ +package bjc.dicelang; + +import bjc.dicelang.dice.Die; +import bjc.dicelang.dice.DieExpression; +import bjc.dicelang.dice.DieList; +import bjc.utils.data.ITree; +import bjc.utils.data.Tree; + +public class EvaluatorResult { + public static enum Type { + FAILURE, + INT, FLOAT, DICE, STRING + } + + public final EvaluatorResult.Type type; + + // These may or may not have values based + // off of the result type + public long intVal; + public double floatVal; + public DieExpression diceVal; + public String stringVal; + + // Original node data + public ITree origVal; + + public EvaluatorResult(EvaluatorResult.Type typ) { + type = typ; + } + + public EvaluatorResult(EvaluatorResult.Type typ, ITree orig) { + this(typ); + + origVal = orig; + } + + public EvaluatorResult(EvaluatorResult.Type typ, Node orig) { + this(typ, new Tree<>(orig)); + } + + public EvaluatorResult(EvaluatorResult.Type typ, EvaluatorResult orig) { + this(typ, new Node(Node.Type.RESULT, orig)); + } + + public EvaluatorResult(EvaluatorResult.Type typ, long iVal) { + this(typ); + + intVal = iVal; + } + + public EvaluatorResult(EvaluatorResult.Type typ, double dVal) { + this(typ); + + floatVal = dVal; + } + + public EvaluatorResult(EvaluatorResult.Type typ, DieExpression dVal) { + this(typ); + + diceVal = dVal; + } + + public EvaluatorResult(EvaluatorResult.Type typ, Die dVal) { + this(typ); + + diceVal = new DieExpression(dVal); + } + + public EvaluatorResult(EvaluatorResult.Type typ, DieList dVal) { + this(typ); + + diceVal = new DieExpression(dVal); + } + + public EvaluatorResult(EvaluatorResult.Type typ, String strang) { + this(typ); + + stringVal = strang; + } + + public String toString() { + switch(type) { + case INT: + return type.toString() + "(" + intVal + ")"; + case FLOAT: + return type.toString() + "(" + floatVal + ")"; + case DICE: + return type.toString() + "(" + diceVal + ")"; + case STRING: + return type.toString() + "(" + stringVal + ")"; + case FAILURE: + return type.toString(); + default: + return "Unknown result type " + type.toString(); + } + } +} \ No newline at end of file diff --git a/dice-lang/src/bjc/dicelang/Node.java b/dice-lang/src/bjc/dicelang/Node.java new file mode 100644 index 0000000..3ae54e3 --- /dev/null +++ b/dice-lang/src/bjc/dicelang/Node.java @@ -0,0 +1,82 @@ +package bjc.dicelang; + +public class Node { + public static enum Type { + ROOT, TOKREF, + UNARYOP, BINOP, + GROUP, OGROUP, + RESULT + } + + public static enum GroupType { + ARRAY, CODE + } + + public final Type type; + + // These can have or not have values based of the node type + public Token tokenVal; + public Token.Type operatorType; + public GroupType groupType; + public EvaluatorResult resultVal; + + public Node(Type typ) { + type = typ; + } + + public Node(Type typ, Token tokenVl) { + this(typ); + + tokenVal = tokenVl; + } + + public Node(Type typ, Token.Type opType) { + this(typ); + + operatorType = opType; + } + + public Node(Type typ, GroupType grupType) { + this(typ); + + groupType = grupType; + } + + public Node(Type typ, EvaluatorResult res) { + this(typ); + + resultVal = res; + } + + public String toString() { + switch(type) { + case UNARYOP: + case BINOP: + return "(" + type.name() + " : " + operatorType + ")"; + case OGROUP: + case TOKREF: + return "(" + type.name() + " : " + tokenVal + ")"; + case GROUP: + return "(" + type.name() + " : " + groupType + ")"; + case RESULT: + return "(" + type.name() + " : " + resultVal + ")"; + default: + return "Unknown node type " + type; + } + } + + public boolean equals(Object other) { + if(!(other instanceof Node)) return false; + + Node otk = (Node)other; + + if(otk.type != type) return false; + + switch(type) { + case OGROUP: + return tokenVal.equals(otk.tokenVal); + default: + return true; + } + } +} diff --git a/dice-lang/src/bjc/dicelang/Parser.java b/dice-lang/src/bjc/dicelang/Parser.java new file mode 100644 index 0000000..4733ced --- /dev/null +++ b/dice-lang/src/bjc/dicelang/Parser.java @@ -0,0 +1,167 @@ +package bjc.dicelang; + +import static bjc.dicelang.Errors.ErrorKey.*; +import static bjc.dicelang.Node.Type.*; +import static bjc.dicelang.Token.Type.*; + +import java.util.Deque; +import java.util.LinkedList; + +import bjc.utils.data.ITree; +import bjc.utils.data.Tree; +import bjc.utils.funcdata.IList; + +public class Parser { + public Parser() { + + } + + public boolean parseTokens(IList tokens, + IList> results) { + Deque> working = new LinkedList<>(); + + for(Token tk : tokens) { + switch(tk.type) { + case OBRACKET: + case OBRACE: + working.push(new Tree<>(new Node(OGROUP, tk))); + break; + case CBRACKET: + case CBRACE: + boolean sc = parseClosingGrouper(working, tk); + if(!sc) return false; + break; + case LET: + case BIND: + if(working.size() < 2) { + Errors.inst.printError(EK_PARSE_BINARY); + return false; + } else { + ITree right = working.pop(); + ITree left = working.pop(); + + ITree opNode = new Tree<>(new Node(BINOP, tk.type)); + + working.push(opNode); + } + break; + case ADD: + case SUBTRACT: + case MULTIPLY: + case DIVIDE: + case IDIVIDE: + case DICEGROUP: + case DICECONCAT: + case DICELIST: + if(working.size() == 0) { + Errors.inst.printError(EK_PARSE_UNOPERAND, tk.toString()); + return false; + } else if(working.size() == 1) { + ITree operand = working.pop(); + + ITree opNode = new Tree<>(new Node(UNARYOP, tk.type)); + + opNode.addChild(operand); + + working.push(opNode); + } else { + ITree right = working.pop(); + ITree left = working.pop(); + + ITree opNode = new Tree<>(new Node(BINOP, tk.type)); + + opNode.addChild(left); + opNode.addChild(right); + + working.push(opNode); + } + break; + case COERCE: + if(working.size() == 0) { + Errors.inst.printError(EK_PARSE_UNOPERAND, tk.toString()); + } else { + ITree operand = working.pop(); + ITree opNode = new Tree<>(new Node(UNARYOP, tk.type)); + + opNode.addChild(operand); + + working.push(opNode); + } + break; + case INT_LIT: + case FLOAT_LIT: + case STRING_LIT: + case VREF: + case DICE_LIT: + working.push(new Tree<>(new Node(TOKREF, tk))); + break; + default: + Errors.inst.printError(EK_PARSE_INVTOKEN, tk.type.toString()); + return false; + } + } + + for(ITree ast : working) { + results.add(ast); + } + + return true; + } + + private boolean parseClosingGrouper(Deque> working, Token tk) { + if(working.size() == 0) { + Errors.inst.printError(EK_PARSE_NOCLOSE); + return false; + } + + ITree groupNode = null; + switch(tk.type) { + case CBRACE: + groupNode = new Tree<>(new Node(GROUP, Node.GroupType.CODE)); + break; + case CBRACKET: + groupNode = new Tree<>(new Node(GROUP, Node.GroupType.ARRAY)); + break; + default: + break; + } + + Token matching = null; + if(tk.type == CBRACKET) { + matching = new Token(Token.Type.OBRACKET, tk.intValue); + } else if(tk.type == CBRACE) { + matching = new Token(Token.Type.OBRACE, tk.intValue); + } + + ITree matchNode = new Tree<>(new Node(OGROUP, matching)); + if(!working.contains(matchNode)) { + Errors.inst.printError(EK_PARSE_UNCLOSE, tk.toString(), matchNode.toString()); + + System.out.println("\tCurrent forest is: "); + + int treeNo = 1; + for(ITree ast : working) { + System.out.println("Tree " + treeNo++ + ": " + ast.toString()); + } + + return false; + } else { + Deque> childs = new LinkedList<>(); + + while(!working.peek().equals(matchNode)) { + childs.push(working.pop()); + } + + // Discard opener + working.pop(); + + for(ITree child : childs) { + groupNode.addChild(child); + } + + working.push(groupNode); + } + + return true; + } +} diff --git a/dice-lang/src/bjc/dicelang/Shunter.java b/dice-lang/src/bjc/dicelang/Shunter.java new file mode 100644 index 0000000..38f49be --- /dev/null +++ b/dice-lang/src/bjc/dicelang/Shunter.java @@ -0,0 +1,258 @@ +package bjc.dicelang; + +import bjc.utils.funcdata.FunctionalList; +import bjc.utils.funcdata.FunctionalMap; +import bjc.utils.funcdata.IList; +import bjc.utils.funcdata.IMap; + +import static bjc.dicelang.Errors.ErrorKey.*; +import static bjc.dicelang.Token.Type.*; + +import java.util.Deque; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Set; + +public class Shunter { + // The binary operators and their + // priorities + private IMap ops; + + // Unary operators that can only be + // applied to non-operator tokens and yield operator tokens + private Set unaryAdjectives; + + // Unary operators that can only be + // applied to operator tokens and yield operator tokens + private Set unaryAdverbs; + + // Unary operators that can only be + // applied to operator tokens and yield data tokens + private Set unaryGerunds; + + private final int MATH_PREC = 20; + private final int DICE_PREC = 10; + private final int EXPR_PREC = 0; + + public Shunter() { + ops = new FunctionalMap<>(); + + unaryAdjectives = new HashSet<>(); + unaryAdverbs = new HashSet<>(); + unaryGerunds = new HashSet<>(); + + unaryAdverbs.add(COERCE); + + ops.put(ADD, 0 + MATH_PREC); + ops.put(SUBTRACT, 0 + MATH_PREC); + + ops.put(MULTIPLY, 1 + MATH_PREC); + ops.put(IDIVIDE, 1 + MATH_PREC); + ops.put(DIVIDE, 1 + MATH_PREC); + + ops.put(DICEGROUP, 0 + DICE_PREC); + + ops.put(DICECONCAT, 1 + DICE_PREC); + + ops.put(DICELIST, 2 + DICE_PREC); + + ops.put(LET, 0 + EXPR_PREC); + ops.put(BIND, 1 + EXPR_PREC); + } + + private boolean isUnary(Token tk) { + Token.Type ty = tk.type; + + if(unaryAdjectives.contains(ty)) return true; + if(unaryAdverbs.contains(ty)) return true; + if(unaryGerunds.contains(ty)) return true; + + return false; + } + + private boolean isOp(Token tk) { + Token.Type ty = tk.type; + + if(ops.containsKey(ty)) return true; + if(unaryAdjectives.contains(ty)) return true; + if(unaryAdverbs.contains(ty)) return true; + if(unaryGerunds.contains(ty)) return true; + if(ty == TAGOPR) return true; + + return false; + } + + private boolean shuntToken(Token tk, Deque opStack, + Deque unaryStack, Deque currReturned, + Deque feed) { + if(unaryStack.size() != 0) { + if(isUnary(tk)) { + unaryStack.add(tk); + return true; + } + + Token unaryOp = unaryStack.pop(); + + Token.Type unaryType = unaryOp.type; + + if(unaryAdjectives.contains(unaryType)) { + if(isOp(tk)) { + Errors.inst.printError(EK_SHUNT_NOTADV, unaryOp.toString(), tk.toString()); + return false; + } + + Token newTok = new Token(TAGOPR); + + if(tk.type == TAGOP) { + newTok.tokenValues = tk.tokenValues; + } else { + newTok.tokenValues = new FunctionalList<>(tk); + } + + newTok.tokenValues.add(unaryOp); + opStack.push(newTok); + + return true; + } else if(unaryAdverbs.contains(unaryType)) { + if(!isOp(tk)) { + Errors.inst.printError(EK_SHUNT_NOTADJ, unaryOp.toString(), tk.toString()); + return false; + } + + Token newTok = new Token(TAGOPR); + + if(tk.type == TAGOP) { + newTok.tokenValues = tk.tokenValues; + } else { + newTok.tokenValues = new FunctionalList<>(tk); + } + + newTok.tokenValues.add(unaryOp); + opStack.push(newTok); + + return true; + } + } + + if(isUnary(tk)) { + unaryStack.add(tk); + return true; + } else if(isOp(tk)) { + while(!opStack.isEmpty() && isHigherPrec(tk, opStack.peek())) { + currReturned.addLast(opStack.pop()); + } + + opStack.push(tk); + } else if(tk.type == OPAREN || tk.type == OBRACE) { + opStack.push(tk); + + if(tk.type == OBRACE) currReturned.addLast(tk); + } else if(tk.type == CPAREN || tk.type == CBRACE) { + Token matching = null; + + switch(tk.type) { + case CPAREN: + matching = new Token(OPAREN, tk.intValue); + break; + case CBRACE: + matching = new Token(OBRACE, tk.intValue); + break; + default: + break; + } + + if(!opStack.contains(matching)) { + Errors.inst.printError(EK_SHUNT_NOGROUP, tk.toString(), matching.toString()); + return false; + } + + while(!opStack.peek().equals(matching)) { + currReturned.addLast(opStack.pop()); + } + + if(tk.type == CBRACE) { + currReturned.addLast(tk); + } + + opStack.pop(); + } else if(tk.type == GROUPSEP) { + IList group = new FunctionalList<>(); + + while(currReturned.size() != 0 && !currReturned.peek().isGrouper()) { + group.add(currReturned.pop()); + } + + while(opStack.size() != 0 && !opStack.peek().isGrouper()) { + group.add(opStack.pop()); + } + + if(currReturned.size() == 0) { + Errors.inst.printError(EK_SHUNT_INVSEP); + return false; + } + + currReturned.addLast(new Token(TOKGROUP, group)); + } else { + currReturned.addLast(tk); + } + + return true; + } + + public boolean shuntTokens(IList tks, IList returned) { + Deque opStack = new LinkedList<>(); + Deque unaryOps = new LinkedList<>(); + + Deque currReturned = new LinkedList<>(); + + Deque feed = new LinkedList<>(); + + for(Token tk : tks.toIterable()) { + while(feed.size() != 0) + shuntToken(feed.poll(), opStack, unaryOps, currReturned, feed); + shuntToken(tk, opStack, unaryOps, currReturned, feed); + } + + // Flush leftover operators + while(!opStack.isEmpty()) { + currReturned.addLast(opStack.pop()); + } + + for(Token tk : currReturned) { + returned.add(tk); + } + + return true; + } + + private boolean isHigherPrec(Token lft, Token rght) { + Token.Type left = lft.type; + Token.Type right = rght.type; + + boolean exists = ops.containsKey(right); + + if(rght.type == TAGOPR) exists = true; + + // If it doesn't, the left is higher precedence. + if (!exists) { + return false; + } + + int rightPrecedence; + int leftPrecedence; + + if(rght.type == TAGOPR) { + rightPrecedence = (int)rght.intValue; + } else { + rightPrecedence = ops.get(right); + } + + if(lft.type == TAGOPR) { + leftPrecedence = (int)lft.intValue; + } else { + leftPrecedence = ops.get(left); + } + + return rightPrecedence >= leftPrecedence; + } +} diff --git a/dice-lang/src/bjc/dicelang/StreamEngine.java b/dice-lang/src/bjc/dicelang/StreamEngine.java new file mode 100644 index 0000000..2971392 --- /dev/null +++ b/dice-lang/src/bjc/dicelang/StreamEngine.java @@ -0,0 +1,118 @@ +package bjc.dicelang; + +import bjc.utils.funcdata.FunctionalList; +import bjc.utils.funcdata.IList; +import bjc.utils.funcutils.ListUtils; + +import static bjc.dicelang.Errors.ErrorKey.*; + +import bjc.utils.esodata.SingleTape; +import bjc.utils.esodata.Tape; + +public class StreamEngine { + private DiceLangEngine eng; + + private Tape> streams; + private IList currStream; + + public StreamEngine(DiceLangEngine engine) { + eng = engine; + } + + private void init() { + streams = new SingleTape<>(); + + currStream = new FunctionalList<>(); + streams.insertBefore(currStream); + } + + public boolean doStreams(String[] toks, IList dest) { + init(); + + boolean quoteMode = false; + + for(String tk : toks) { + if(tk.startsWith("{@S") && !quoteMode) { + if(tk.equals("{@SQ}")) { + quoteMode = true; + } else if(!processCommand(tk)) { + return false; + } + // Command ran correctly, continue + } else { + if(tk.equals("{@SU}")) { + quoteMode = false; + } else if(tk.startsWith("\\") && tk.endsWith("{@SU}")) { + currStream.add(tk.substring(1)); + } else { + currStream.add(tk); + } + } + } + + for(String tk : currStream) { + dest.add(tk); + } + + return true; + } + + private boolean processCommand(String tk) { + char[] comms = null; + + if(tk.length() > 5) { + comms = tk.substring(3, tk.length() - 1).toCharArray(); + } else { + comms = new char[1]; + comms[0] = tk.charAt(3); + } + + for(char comm : comms) { + switch(comm) { + case '+': + streams.insertAfter(new FunctionalList<>()); + break; + case '>': + if(!streams.right()) { + Errors.inst.printError(EK_STRM_NONEX); + return false; + } + + currStream = streams.item(); + break; + case '<': + if(!streams.left()) { + Errors.inst.printError(EK_STRM_NONEX); + return false; + } + + currStream = streams.item(); + break; + case '-': + if(streams.size() == 1) { + Errors.inst.printError(EK_STRM_LAST); + return false; + } else { + streams.remove(); + currStream = streams.item(); + } + break; + case 'S': + if(streams.size() == 1) { + Errors.inst.printError(EK_STRM_LAST); + return false; + } else { + IList stringLit = streams.remove(); + currStream = streams.item(); + currStream.add(ListUtils.collapseTokens(stringLit, " ")); + } + break; + default: + Errors.inst.printError(EK_STRM_INVCOM, tk); + return false; + } + } + + return true; + } +} diff --git a/dice-lang/src/bjc/dicelang/Token.java b/dice-lang/src/bjc/dicelang/Token.java new file mode 100644 index 0000000..c022fe1 --- /dev/null +++ b/dice-lang/src/bjc/dicelang/Token.java @@ -0,0 +1,140 @@ +package bjc.dicelang; + +import bjc.dicelang.dice.DieExpression; +import bjc.utils.funcdata.IList; + +/** + * Lexer token + */ +public class Token { + public final static Token NIL_TOKEN = new Token(Type.NIL); + + /** + * Possible token types + */ + public static enum Type { + // Natural tokens + // These are produced from lexemes + ADD, SUBTRACT, + MULTIPLY, + DIVIDE, IDIVIDE, + INT_LIT, FLOAT_LIT, STRING_LIT, + VREF, + DICE_LIT, DICEGROUP, DICECONCAT, DICELIST, + LET, BIND, COERCE, + OPAREN, CPAREN, + OBRACKET, CBRACKET, + OBRACE, CBRACE, + + // Synthetic tokens + // These are produced when needed + NIL, GROUPSEP, TOKGROUP, + TAGOP, TAGOPR + } + + public final Type type; + + // This is used for the following token types + // INT_LIT (int value) + // STRING_LIT (index into string table) + // VREF (index into sym table) + // O* and C* (sym-count of current token) + public long intValue; + + // This is used for the following token types + // FLOAT_LIT (float value) + public double floatValue; + + // This is used for the following token types + // DICE_LIT (dice value) + public DieExpression diceValue; + + // This is used for the following token types + // TOKGROUP (the tokens in the group) + // TAG* (the tagged construct) + public IList tokenValues; + + public Token(Type typ) { + type = typ; + } + + public Token(Type typ, long val) { + this(typ); + + intValue = val; + } + + public Token(Type typ, double val) { + this(typ); + + floatValue = val; + } + + public Token(Type typ, DieExpression val) { + this(typ); + + diceValue = val; + } + + public Token(Type typ, IList tkVals) { + this(typ); + + tokenValues = tkVals; + } + + public String toString() { + switch(type) { + case INT_LIT: + case STRING_LIT: + case VREF: + case OPAREN: + case CPAREN: + case OBRACKET: + case CBRACKET: + case OBRACE: + case CBRACE: + return type.toString() + "(" + + intValue + ")"; + case FLOAT_LIT: + return type.toString() + "(" + + floatValue + ")"; + case DICE_LIT: + return type.toString() + "(" + + diceValue + ")"; + case TAGOP: + case TAGOPR: + case TOKGROUP: + return type.toString() + "(" + + tokenValues + ")"; + default: + return type.toString(); + } + } + + public boolean equals(Object other) { + if(!(other instanceof Token)) return false; + + Token otk = (Token)other; + + if(otk.type != type) return false; + + switch(type) { + case OBRACE: + case OBRACKET: + return intValue == otk.intValue; + default: + return true; + } + } + + public boolean isGrouper() { + switch(type) { + case OPAREN: + case OBRACE: + case OBRACKET: + return true; + default: + return false; + } + } +} diff --git a/dice-lang/src/bjc/dicelang/Tokenizer.java b/dice-lang/src/bjc/dicelang/Tokenizer.java new file mode 100644 index 0000000..532a6a4 --- /dev/null +++ b/dice-lang/src/bjc/dicelang/Tokenizer.java @@ -0,0 +1,154 @@ +package bjc.dicelang; + +import static bjc.dicelang.Errors.ErrorKey.*; +import static bjc.dicelang.Token.Type.*; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import bjc.dicelang.dice.DiceBox; +import bjc.utils.funcdata.FunctionalMap; +import bjc.utils.funcdata.IMap; +import bjc.utils.funcutils.StringUtils; + +public class Tokenizer { + // Literal tokens for tokenization + private IMap litTokens; + + private DiceLangEngine eng; + + private int nextSym = 0; + + public Tokenizer(DiceLangEngine engine) { + eng = engine; + + litTokens = new FunctionalMap<>(); + + litTokens.put("+", ADD); + litTokens.put("-", SUBTRACT); + litTokens.put("*", MULTIPLY); + litTokens.put("/", DIVIDE); + litTokens.put("//", IDIVIDE); + litTokens.put("dg", DICEGROUP); + litTokens.put("dc", DICECONCAT); + litTokens.put("dl", DICELIST); + litTokens.put("=>", LET); + litTokens.put(":=", BIND); + litTokens.put(",", GROUPSEP); + litTokens.put("crc", COERCE); + } + + public Token lexToken(String token, IMap stringLts) { + if(token.equals("")) return null; + + Token tk = Token.NIL_TOKEN; + + if(litTokens.containsKey(token)) { + tk = new Token(litTokens.get(token)); + } else { + switch(token.charAt(0)) { + case '(': + case ')': + case '[': + case ']': + case '{': + case '}': + tk = tokenizeGrouping(token); + break; + default: + tk = tokenizeLiteral(token, stringLts); + } + } + + return tk; + } + + private Token tokenizeGrouping(String token) { + Token tk = Token.NIL_TOKEN; + + if(StringUtils.containsOnly(token, "\\" + token.charAt(0))) { + switch(token.charAt(0)) { + case '(': + tk = new Token(OPAREN, token.length()); + break; + case ')': + tk = new Token(CPAREN, token.length()); + break; + case '[': + tk = new Token(OBRACKET, token.length()); + break; + case ']': + tk = new Token(CBRACKET, token.length()); + break; + case '{': + tk = new Token(OBRACE, token.length()); + break; + case '}': + tk = new Token(CBRACE, token.length()); + break; + default: + Errors.inst.printError(EK_TOK_UNGROUP, token); + break; + } + } + + return tk; + } + + private Pattern intMatcher = Pattern.compile("\\A[\\-\\+]?\\d+\\Z"); + private Pattern hexadecimalMatcher = Pattern.compile("\\A[\\-\\+]?0x[0-9A-Fa-f]+\\Z"); + private Pattern flexadecimalMatcher = Pattern.compile("\\A[\\-\\+]?[0-9][0-9A-Za-z]+B\\d{1,2}\\Z"); + private Pattern stringLitMatcher = Pattern.compile("\\AstringLiteral(\\d+)\\Z"); + + private Token tokenizeLiteral(String token, IMap stringLts) { + Token tk = Token.NIL_TOKEN; + + if(intMatcher.matcher(token).matches()) { + tk = new Token(INT_LIT, Long.parseLong(token)); + } else if(hexadecimalMatcher.matcher(token).matches()) { + String newToken = token.substring(0, 1) + token.substring(token.indexOf('x')); + + tk = new Token(INT_LIT, Long.parseLong(newToken.substring(2).toUpperCase(), 16)); + } else if(flexadecimalMatcher.matcher(token).matches()) { + int parseBase = Integer.parseInt(token.substring(token.lastIndexOf('B') + 1)); + + if(parseBase < Character.MIN_RADIX || parseBase > Character.MAX_RADIX) { + Errors.inst.printError(EK_TOK_INVBASE, Integer.toString(parseBase)); + return Token.NIL_TOKEN; + } + + String flexNum = token.substring(0, token.lastIndexOf('B')); + + try { + tk = new Token(INT_LIT, Long.parseLong(flexNum, parseBase)); + } catch (NumberFormatException nfex) { + Errors.inst.printError(EK_TOK_INVFLEX, flexNum, Integer.toString(parseBase)); + return Token.NIL_TOKEN; + } + } else if(DoubleMatcher.floatingLiteral.matcher(token).matches()) { + tk = new Token(FLOAT_LIT, Double.parseDouble(token)); + } else if(DiceBox.isValidExpression(token)) { + tk = new Token(DICE_LIT, DiceBox.parseExpression(token)); + } else { + Matcher stringLit = stringLitMatcher.matcher(token); + + if(stringLit.matches()) { + int litNum = Integer.parseInt(stringLit.group(1)); + + eng.stringLits.put(litNum, stringLts.get(token)); + tk = new Token(STRING_LIT, litNum); + } else { + // @TODO define what a valid identifier is + eng.symTable.put(nextSym++, token); + + tk = new Token(VREF, nextSym - 1); + } + + // @TODO uncomment when we have a defn. for var names + // System.out.printf("\tERROR: Unrecognized token:" + // + "%s\n", token); + } + + return tk; + } +} diff --git a/dice-lang/src/bjc/dicelang/dice/CompoundDie.java b/dice-lang/src/bjc/dicelang/dice/CompoundDie.java new file mode 100644 index 0000000..16aec76 --- /dev/null +++ b/dice-lang/src/bjc/dicelang/dice/CompoundDie.java @@ -0,0 +1,31 @@ +package bjc.dicelang.dice; + +public class CompoundDie implements Die { + private Die left; + private Die right; + + public CompoundDie(Die lft, Die rght) { + left = lft; + right = rght; + } + + public boolean canOptimize() { + return left.canOptimize() && right.canOptimize(); + } + + public long optimize() { + return Long.parseLong(left.optimize() + "" + right.optimize()); + } + + public long roll() { + return Long.parseLong(left.roll() + "" + right.roll()); + } + + public long rollSingle() { + return roll(); + } + + public String toString() { + return left.toString() + "c" + right.toString(); + } +} \ No newline at end of file diff --git a/dice-lang/src/bjc/dicelang/dice/CompoundingDie.java b/dice-lang/src/bjc/dicelang/dice/CompoundingDie.java new file mode 100644 index 0000000..9744650 --- /dev/null +++ b/dice-lang/src/bjc/dicelang/dice/CompoundingDie.java @@ -0,0 +1,63 @@ +package bjc.dicelang.dice; + +import java.util.function.Predicate; + +public class CompoundingDie implements Die { + private Die source; + + private Predicate compoundOn; + private String compoundPattern; + + public CompoundingDie(Die src, Predicate compound) { + this(src, compound, null); + } + + public CompoundingDie(Die src, Predicate compound, String patt) { + source = src; + + compoundOn = compound; + compoundPattern = patt; + } + + public boolean canOptimize() { + return source.canOptimize() && source.optimize() == 0; + } + + public long optimize() { + return 0; + } + + public long roll() { + long res = source.roll(); + long oldRes = res; + + while(compoundOn.test(oldRes)) { + oldRes = source.rollSingle(); + + res += oldRes; + } + + return res; + } + + public long rollSingle() { + long res = source.rollSingle(); + long oldRes = res; + + while(compoundOn.test(oldRes)) { + oldRes = source.rollSingle(); + + res += oldRes; + } + + return res; + } + + public String toString() { + if(compoundPattern == null) { + return source + "!!"; + } else { + return source + "!!" + compoundPattern; + } + } +} \ No newline at end of file diff --git a/dice-lang/src/bjc/dicelang/dice/DiceBox.java b/dice-lang/src/bjc/dicelang/dice/DiceBox.java new file mode 100644 index 0000000..4c0641a --- /dev/null +++ b/dice-lang/src/bjc/dicelang/dice/DiceBox.java @@ -0,0 +1,142 @@ +package bjc.dicelang.dice; + +import java.util.Random; +import java.util.function.Predicate; +import java.util.regex.Pattern; + +public class DiceBox { + static final Random rng = new Random(); + + public static DieExpression parseExpression(String exp) { + if(!isValidExpression(exp)) return null; + + if(scalarDiePattern.matcher(exp).matches()) { + Die scal = new ScalarDie(Long.parseLong(exp.substring(0, exp.indexOf('s')))); + + return new DieExpression(scal); + } else if(simpleDiePattern.matcher(exp).matches()) { + String[] dieParts = exp.split("d"); + + long right = Long.parseLong(dieParts[1]); + if(dieParts[0].equals("")) { + Die scal = new SimpleDie(1, right); + return new DieExpression(scal); + } else { + Die scal = new SimpleDie(Long.parseLong(dieParts[0]), right); + return new DieExpression(scal); + } + } else if(fudgeDiePattern.matcher(exp).matches()) { + String nDice = exp.substring(0, exp.indexOf('d')); + + return new DieExpression(new FudgeDie(Long.parseLong(nDice))); + } else if(compoundDiePattern.matcher(exp).matches()) { + String[] dieParts = exp.split("c"); + + DieExpression left = parseExpression(dieParts[0]); + DieExpression right = parseExpression(dieParts[1]); + + return new DieExpression(new CompoundDie(left.scalar, right.scalar)); + } else if(compoundingDiePattern.matcher(exp).matches()) { + String[] dieParts = exp.split("!!"); + + DieExpression left = parseExpression(dieParts[0]); + Predicate right = deriveCond(dieParts[1]); + + Die scal = new CompoundingDie(left.scalar, right, dieParts[1]); + return new DieExpression(scal); + } else if(explodingDiePattern.matcher(exp).matches()) { + String[] dieParts = exp.split("!"); + + DieExpression left = parseExpression(dieParts[0]); + Predicate right = deriveCond(dieParts[1]); + + DieList lst = new ExplodingDice(left.scalar, right, dieParts[1], false); + return new DieExpression(lst); + } else if(penetratingDiePattern.matcher(exp).matches()) { + String[] dieParts = exp.split("p!"); + + DieExpression left = parseExpression(dieParts[0]); + Predicate right = deriveCond(dieParts[1]); + + DieList lst = new ExplodingDice(left.scalar, right, dieParts[1], true); + return new DieExpression(lst); + } else if(diceListPattern.matcher(exp).matches()) { + String[] dieParts = exp.split("dl"); + + DieExpression left = parseExpression(dieParts[0]); + DieExpression right = parseExpression(dieParts[1]); + + DieList lst = new SimpleDieList(left.scalar, right.scalar); + return new DieExpression(lst); + } + + // @TODO give a specific error message + return null; + } + + private static final String comparePoint = "[<>=]\\d+"; + + private static final String scalarDie = "[\\+\\-]?\\d+sd"; + private static final Pattern scalarDiePattern = Pattern.compile("\\A" + scalarDie + "\\Z"); + + private static final String simpleDie = "(?:\\d+)?d\\d+"; + private static final Pattern simpleDiePattern = Pattern.compile("\\A" + simpleDie + "\\Z"); + + private static final String fudgeDie = "(?:\\d+)?dF"; + private static final Pattern fudgeDiePattern = Pattern.compile("\\A" + fudgeDie + "\\Z"); + + private static final String compoundDie = simpleDie + "c(?:(?:" + simpleDie + ")|(?:\\d+))"; + private static final Pattern compoundDiePattern = Pattern.compile("\\A" + compoundDie + "\\Z"); + + private static final String compoundGroup = "(?:(?:" + scalarDie + ")|(?:" + simpleDie + ")|(?:" + + compoundDie + ")|(?:" + fudgeDie +"))"; + + private static final String compoundingDie = compoundGroup + "!!" + comparePoint; + private static final Pattern compoundingDiePattern = Pattern.compile("\\A" + compoundingDie + "\\Z"); + + private static final String explodingDie = compoundGroup + "!" + comparePoint; + private static final Pattern explodingDiePattern = Pattern.compile("\\A" + explodingDie + "\\Z"); + + private static final String penetratingDie = compoundGroup + "!" + comparePoint; + private static final Pattern penetratingDiePattern = Pattern.compile("\\A" + penetratingDie + "\\Z"); + + private static final String diceList = compoundGroup + "dl" + compoundGroup; + private static final Pattern diceListPattern = Pattern.compile("\\A" + diceList + "\\Z"); + + public static boolean isValidExpression(String exp) { + if(scalarDiePattern.matcher(exp).matches()) { + return true; + } else if(simpleDiePattern.matcher(exp).matches()) { + return true; + } else if(fudgeDiePattern.matcher(exp).matches()) { + return true; + } else if(compoundDiePattern.matcher(exp).matches()) { + return true; + } else if(compoundingDiePattern.matcher(exp).matches()) { + return true; + } else if(explodingDiePattern.matcher(exp).matches()) { + return true; + } else if(penetratingDiePattern.matcher(exp).matches()) { + return true; + } else if (diceListPattern.matcher(exp).matches()) { + return true; + } else { + return false; + } + } + + private static Predicate deriveCond(String patt) { + long num = Long.parseLong(patt.substring(1)); + + switch(patt.charAt(0)) { + case '<': + return (roll) -> roll < num; + case '=': + return (roll) -> roll == num; + case '>': + return (roll) -> roll > num; + default: + return (roll) -> false; + } + } +} diff --git a/dice-lang/src/bjc/dicelang/dice/Die.java b/dice-lang/src/bjc/dicelang/dice/Die.java new file mode 100644 index 0000000..9f839ed --- /dev/null +++ b/dice-lang/src/bjc/dicelang/dice/Die.java @@ -0,0 +1,9 @@ +package bjc.dicelang.dice; + +public interface Die { + boolean canOptimize(); + long optimize(); + + long roll(); + long rollSingle(); +} \ No newline at end of file diff --git a/dice-lang/src/bjc/dicelang/dice/DieExpression.java b/dice-lang/src/bjc/dicelang/dice/DieExpression.java new file mode 100644 index 0000000..3bf121b --- /dev/null +++ b/dice-lang/src/bjc/dicelang/dice/DieExpression.java @@ -0,0 +1,30 @@ +package bjc.dicelang.dice; + +import java.util.Arrays; + +public class DieExpression { + public final boolean isList; + + public Die scalar; + public DieList list; + + public DieExpression(Die scal) { + isList = false; + scalar = scal; + } + + public DieExpression(DieList lst) { + isList = true; + list = lst; + } + + public String toString() { + if(isList) return list.toString(); + else return scalar.toString(); + } + + public String value() { + if(isList) return Arrays.toString(list.roll()); + else return Long.toString(scalar.roll()); + } +} \ No newline at end of file diff --git a/dice-lang/src/bjc/dicelang/dice/DieList.java b/dice-lang/src/bjc/dicelang/dice/DieList.java new file mode 100644 index 0000000..a55f2b9 --- /dev/null +++ b/dice-lang/src/bjc/dicelang/dice/DieList.java @@ -0,0 +1,8 @@ +package bjc.dicelang.dice; + +public interface DieList { + boolean canOptimize(); + long[] optimize(); + + long[] roll(); +} \ No newline at end of file diff --git a/dice-lang/src/bjc/dicelang/dice/ExplodingDice.java b/dice-lang/src/bjc/dicelang/dice/ExplodingDice.java new file mode 100644 index 0000000..6ab9902 --- /dev/null +++ b/dice-lang/src/bjc/dicelang/dice/ExplodingDice.java @@ -0,0 +1,70 @@ +package bjc.dicelang.dice; + +import java.util.LinkedList; +import java.util.List; +import java.util.function.Predicate; + +public class ExplodingDice implements DieList { + private Die source; + + private Predicate explodeOn; + private String explodePattern; + private boolean explodePenetrates; + + public ExplodingDice(Die src, Predicate explode) { + this(src, explode, null, false); + } + + public ExplodingDice(Die src, Predicate explode, boolean penetrate) { + this(src, explode, null, penetrate); + } + + public ExplodingDice(Die src, Predicate explode, String patt, + boolean penetrate) { + source = src; + explodeOn = explode; + explodePattern = patt; + explodePenetrates = penetrate; + } + + public boolean canOptimize() { + return false; + } + + public long[] optimize() { + return new long[0]; + } + + public long[] roll() { + long res = source.roll(); + long oldRes = res; + + List resList = new LinkedList<>(); + + while(explodeOn.test(oldRes)) { + oldRes = source.rollSingle(); + + if(explodePenetrates) oldRes -= 1; + resList.add(oldRes); + } + + long[] newRes = new long[resList.size() + 1]; + newRes[0] = res; + + int i = 1; + for(long rll : resList) { + newRes[i] = rll; + i += 1; + } + + return newRes; + } + + public String toString() { + if(explodePattern == null) { + return source + (explodePenetrates ? "p" : "") + "!"; + } else { + return source + (explodePenetrates ? "p" : "") + "!" + explodePattern; + } + } +} \ No newline at end of file diff --git a/dice-lang/src/bjc/dicelang/dice/FudgeDie.java b/dice-lang/src/bjc/dicelang/dice/FudgeDie.java new file mode 100644 index 0000000..ca4fb73 --- /dev/null +++ b/dice-lang/src/bjc/dicelang/dice/FudgeDie.java @@ -0,0 +1,37 @@ +package bjc.dicelang.dice; + +public class FudgeDie implements Die { + private Die numDice; + + public FudgeDie(long nDice) { + numDice = new ScalarDie(nDice); + } + + public boolean canOptimize() { + return numDice.canOptimize() && numDice.optimize() == 0; + } + + public long optimize() { + return 0; + } + + public long roll() { + long res = 0; + + long nDice = numDice.roll(); + + for(int i = 0; i < nDice; i++) { + res += rollSingle(); + } + + return res; + } + + public long rollSingle() { + return DiceBox.rng.nextInt(3) - 1; + } + + public String toString() { + return numDice + "dF"; + } +} \ No newline at end of file diff --git a/dice-lang/src/bjc/dicelang/dice/MathDie.java b/dice-lang/src/bjc/dicelang/dice/MathDie.java new file mode 100644 index 0000000..7e9204d --- /dev/null +++ b/dice-lang/src/bjc/dicelang/dice/MathDie.java @@ -0,0 +1,74 @@ +package bjc.dicelang.dice; + +public class MathDie implements Die { + public static enum MathOp { + ADD, SUBTRACT, MULTIPLY; + + public String toString() { + switch(this) { + case ADD: + return "+"; + case SUBTRACT: + return "-"; + case MULTIPLY: + return "*"; + default: + return this.name(); + } + } + } + + private MathDie.MathOp type; + + private Die left; + private Die right; + + public MathDie(MathDie.MathOp op, Die lft, Die rght) { + type = op; + + left = lft; + right = rght; + } + + public boolean canOptimize() { + return left.canOptimize() && right.canOptimize(); + } + + private long performOp(long lft, long rght) { + switch(type) { + case ADD: + return lft + rght; + case SUBTRACT: + return lft - rght; + case MULTIPLY: + return lft * rght; + default: + return 0; + } + } + + public long optimize() { + long lft = left.optimize(); + long rght = right.optimize(); + + return performOp(lft, rght); + } + + public long roll() { + long lft = left.roll(); + long rght = right.roll(); + + return performOp(lft, rght); + } + + public long rollSingle() { + long lft = left.rollSingle(); + long rght = right.rollSingle(); + + return performOp(lft, rght); + } + + public String toString() { + return left.toString() + " " + type.toString() + " " + right.toString(); + } +} \ No newline at end of file diff --git a/dice-lang/src/bjc/dicelang/dice/ScalarDie.java b/dice-lang/src/bjc/dicelang/dice/ScalarDie.java new file mode 100644 index 0000000..ac64d1c --- /dev/null +++ b/dice-lang/src/bjc/dicelang/dice/ScalarDie.java @@ -0,0 +1,29 @@ +package bjc.dicelang.dice; + +public class ScalarDie implements Die { + private long val; + + public ScalarDie(long vl) { + val = vl; + } + + public boolean canOptimize() { + return true; + } + + public long optimize() { + return val; + } + + public long roll() { + return val; + } + + public long rollSingle() { + return val; + } + + public String toString() { + return Long.toString(val); + } +} \ No newline at end of file diff --git a/dice-lang/src/bjc/dicelang/dice/SimpleDie.java b/dice-lang/src/bjc/dicelang/dice/SimpleDie.java new file mode 100644 index 0000000..5ba76ef --- /dev/null +++ b/dice-lang/src/bjc/dicelang/dice/SimpleDie.java @@ -0,0 +1,60 @@ +package bjc.dicelang.dice; + +public class SimpleDie implements Die { + private Die numDice; + private Die diceSize; + + public SimpleDie(long nDice, long size) { + numDice = new ScalarDie(nDice); + diceSize = new ScalarDie(size); + } + + public SimpleDie(Die nDice, long size) { + numDice = nDice; + diceSize = new ScalarDie(size); + } + + public SimpleDie(long nDice, Die size) { + numDice = new ScalarDie(nDice); + diceSize = size; + } + + public SimpleDie(Die nDice, Die size) { + numDice = nDice; + diceSize = size; + } + + public boolean canOptimize() { + if(diceSize.canOptimize() && (diceSize.optimize() <= 1)) { + return numDice.canOptimize(); + } else return false; + } + + public long optimize() { + long optSize = diceSize.optimize(); + + if(optSize == 0) return 0; + else return numDice.optimize(); + } + + public long roll() { + long total = 0; + + long nDice = numDice.roll(); + long dSize = diceSize.roll(); + + for(int i = 0; i < nDice; i++) { + total += (Math.abs(DiceBox.rng.nextLong()) % dSize) + 1; + } + + return total; + } + + public long rollSingle() { + return (Math.abs(DiceBox.rng.nextLong()) % diceSize.roll()) + 1; + } + + public String toString() { + return numDice + "d" + diceSize; + } +} \ No newline at end of file diff --git a/dice-lang/src/bjc/dicelang/dice/SimpleDieList.java b/dice-lang/src/bjc/dicelang/dice/SimpleDieList.java new file mode 100644 index 0000000..cca1f04 --- /dev/null +++ b/dice-lang/src/bjc/dicelang/dice/SimpleDieList.java @@ -0,0 +1,48 @@ +package bjc.dicelang.dice; + +public class SimpleDieList implements DieList { + private Die numDice; + private Die size; + + public SimpleDieList(Die nDice, Die sze) { + numDice = nDice; + size = sze; + } + + public boolean canOptimize() { + if(size.canOptimize() && size.optimize() <= 1) { + return numDice.canOptimize(); + } else { + return false; + } + } + + public long[] optimize() { + int sze = (int)numDice.optimize(); + long res = size.optimize(); + + long[] ret = new long[sze]; + + for(int i = 0; i < sze; i++) { + ret[i] = res; + } + + return ret; + } + + public long[] roll() { + int num = (int)numDice.roll(); + + long[] ret = new long[num]; + + for(int i = 0; i < num; i++) { + ret[i] = size.roll(); + } + + return ret; + } + + public String toString() { + return numDice.toString() + "dl" + size.toString(); + } +} \ No newline at end of file diff --git a/dice-lang/src/bjc/dicelang/v2/Define.java b/dice-lang/src/bjc/dicelang/v2/Define.java deleted file mode 100644 index 5af91ea..0000000 --- a/dice-lang/src/bjc/dicelang/v2/Define.java +++ /dev/null @@ -1,125 +0,0 @@ -package bjc.dicelang.v2; - -import bjc.utils.data.CircularIterator; - -import static bjc.dicelang.v2.Errors.ErrorKey.*; - -import java.util.Iterator; -import java.util.function.UnaryOperator; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -public class Define implements UnaryOperator { - public static enum Type { LINE, TOKEN } - - public static final int MAX_RECURS = 10; - - public final int priority; - public final boolean inError; - - private boolean doRecur; - private boolean subType; - - private Pattern predicate; - private Pattern searcher; - - private Iterator replacers; - private String replacer; - - public Define(int priorty, - boolean isSub, boolean recur, boolean isCircular, - String predicte, String searchr, Iterable replacrs) { - priority = priorty; - doRecur = recur; - subType = isSub; - - if(predicte != null) { - try { - predicate = Pattern.compile(predicte); - } catch (PatternSyntaxException psex) { - Errors.inst.printError(EK_DFN_PREDSYN, psex.getMessage()); - inError = true; - return; - } - } - - try { - searcher = Pattern.compile(searchr); - } catch (PatternSyntaxException psex) { - Errors.inst.printError(EK_DFN_SRCSYN, psex.getMessage()); - inError = true; - return; - } - - inError = false; - - if(subType) { - if(replacrs.iterator().hasNext()) { - replacers = new CircularIterator<>(replacrs, isCircular); - } else { - replacers = null; - } - } else { - Iterator itr = replacrs.iterator(); - - if(itr.hasNext()) replacer = itr.next(); - else replacer = ""; - } - } - - public String apply(String tok) { - if(inError) return tok; - - if(predicate != null) { - if(!predicate.matcher(tok).matches()) { - return tok; - } - } - - String strang = doPass(tok); - - if(doRecur) { - int recurCount = 0; - - if(strang.equals(tok)) { - return strang; - } else { - String oldStrang = strang; - - do { - strang = doPass(tok); - recurCount += 1; - } while(!strang.equals(oldStrang) && recurCount < MAX_RECURS); - - if(recurCount >= MAX_RECURS) { - Errors.inst.printError(EK_DFN_RECUR, Integer.toString(MAX_RECURS), tok, strang); - return strang; - } - } - } - - return strang; - } - - private String doPass(String tok) { - Matcher searcherMatcher = searcher.matcher(tok); - - if(subType) { - StringBuffer sb = new StringBuffer(); - while(searcherMatcher.find()) { - if(replacers == null) { - searcherMatcher.appendReplacement(sb,""); - } else { - String replac = replacers.next(); - searcherMatcher.appendReplacement(sb, replac); - } - } - - searcherMatcher.appendTail(sb); - return sb.toString(); - } else { - return searcherMatcher.replaceAll(replacer); - } - } -} diff --git a/dice-lang/src/bjc/dicelang/v2/DiceLangConsole.java b/dice-lang/src/bjc/dicelang/v2/DiceLangConsole.java deleted file mode 100644 index 7f3c85b..0000000 --- a/dice-lang/src/bjc/dicelang/v2/DiceLangConsole.java +++ /dev/null @@ -1,261 +0,0 @@ -package bjc.dicelang.v2; - -import static bjc.dicelang.v2.Errors.ErrorKey.*; - -import java.io.IOException; -import java.util.List; -import java.util.LinkedList; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import jline.ConsoleReader; -import jline.Terminal; - -public class DiceLangConsole { - private int commandNumber; - - private DiceLangEngine eng; - - private ConsoleReader read; - - public DiceLangConsole(String[] args) { - // @TODO do something with the args - commandNumber = 0; - - eng = new DiceLangEngine(); - - Terminal.setupTerminal(); - } - - public void run() { - try { - read = new ConsoleReader(); - } catch(IOException ioex) { - System.out.println("ERROR: Console init failed"); - return; - } - - System.out.println("dice-lang v0.2"); - - String comm = null; - - try { - comm = read.readLine(String.format("(%d) dice-lang> ", commandNumber)); - } catch (IOException ioex) { - System.out.println("ERROR: I/O failed"); - return; - } - - while(!comm.equals("quit") && !comm.equals("exit")) { - if(comm.startsWith("pragma")) { - boolean success = handlePragma(comm.substring(7)); - - if(success) System.out.println("Pragma completed succesfully"); - else System.out.println("Pragma execution failed"); - } else { - System.out.printf("\tRaw command: %s\n", comm); - - boolean success = eng.runCommand(comm); - - if(success) System.out.println("Command completed succesfully"); - else System.out.println("Command execution failed"); - - commandNumber += 1; - } - - try { - comm = read.readLine(String.format("(%d) dice-lang> ", commandNumber)); - } catch (IOException ioex) { - System.out.println("ERROR: I/O failed"); - return; - } - } - } - - private boolean handlePragma(String pragma) { - System.out.println("\tRaw pragma: " + pragma); - - String pragmaName = null; - int firstIndex = pragma.indexOf(' '); - if(firstIndex == -1) { - pragmaName = pragma; - } else { - pragmaName = pragma.substring(0, firstIndex); - } - - switch(pragmaName) { - case "debug": - System.out.println("\tDebug mode is now " + eng.toggleDebug()); - break; - case "postfix": - System.out.println("\tPostfix mode is now " + eng.togglePostfix()); - break; - case "prefix": - System.out.println("\tPrefix mode is now " + eng.togglePrefix()); - break; - case "stepeval": - System.out.println("\tStepeval mode is now" + eng.toggleStepEval()); - break; - case "define": - return defineMode(pragma.substring(7)); - case "help": - return helpMode(pragma.substring(5)); - default: - Errors.inst.printError(EK_CONS_INVPRAG, pragma); - return false; - } - - return true; - } - - private boolean helpMode(String pragma) { - switch(pragma.trim()) { - case "help": - System.out.println("\tGet help on pragmas"); - break; - case "debug": - System.out.println("\tToggle debug mode. (Output stage results)"); - break; - case "postfix": - System.out.println("\tToggle postfix mode. (Don't shunt tokens)"); - break; - case "prefix": - System.out.println("\tToggle prefix mode. (Reverse token order instead of shunting)"); - break; - case "stepeval": - System.out.println("\tToggle stepeval mode. (Print out evaluation progress)"); - break; - case "define": - System.out.println("\tAdd a macro rewrite directive."); - System.out.println("\tdefine ..."); - break; - default: - System.out.println("\tNo help available for pragma " + pragma); - } - - // Help always works - return true; - } - - /* - * Matches slash-delimited strings - * (like /text/ or /text\/text/) - * Uses the "normal* (special normal*)*" pattern style - * recommended in 'Mastering regular expressions' - * Here, the normal is 'anything but a forward or backslash' - * (in regex, thats '[^/\\]') and the special is 'an escaped forward slash' - * (in regex, thats '\\\\/') - * - * Then, we just follow the pattern, escape it for java strings, and - * add the enclosing slashes - */ - private Pattern slashPattern = Pattern.compile("/((?:\\\\.|[^/\\\\])*)/"); - - private boolean defineMode(String defineText) { - int firstIndex = defineText.indexOf(' '); - int secondIndex = defineText.indexOf(' ', firstIndex + 1); - int thirdIndex = defineText.indexOf(' ', secondIndex + 1); - int fourthIndex = defineText.indexOf(' ', thirdIndex + 1); - int fifthIndex = defineText.indexOf(' ', fourthIndex + 1); - int sixthIndex = defineText.indexOf(' ', fifthIndex + 1); - - if(firstIndex == -1) { - Errors.inst.printError(EK_CONS_INVDEFINE, "(no priority)"); - return false; - } else if(secondIndex == -1) { - Errors.inst.printError(EK_CONS_INVDEFINE, "(no define type)"); - return false; - } else if(thirdIndex == -1) { - Errors.inst.printError(EK_CONS_INVDEFINE, "(no recursion type)"); - return false; - } else if(fourthIndex == -1) { - Errors.inst.printError(EK_CONS_INVDEFINE, "(no guard type)"); - return false; - } else if(fifthIndex == -1) { - Errors.inst.printError(EK_CONS_INVDEFINE, "(no circularity)"); - return false; - } else if(sixthIndex == -1) { - Errors.inst.printError(EK_CONS_INVDEFINE, "(no patterns)"); - return false; - } - - int priority = Integer.parseInt(defineText.substring(0, firstIndex)); - - String defineType = defineText.substring(firstIndex + 1, secondIndex); - - Define.Type type; - boolean subMode = false; - - switch(defineType) { - case "line": - type = Define.Type.LINE; - break; - case "token": - type = Define.Type.TOKEN; - break; - case "subline": - type = Define.Type.LINE; - subMode = true; - break; - case "subtoken": - type = Define.Type.TOKEN; - subMode = true; - break; - default: - Errors.inst.printError(EK_CONS_INVDEFINE, "(unknown type)"); - return false; - } - - boolean doRecur = defineText.substring(secondIndex + 1, thirdIndex) - .equalsIgnoreCase("true"); - boolean hasGuard = defineText.substring(thirdIndex + 1, fourthIndex) - .equalsIgnoreCase("true"); - boolean isCircular = defineText.substring(thirdIndex + 1, fourthIndex) - .equalsIgnoreCase("true"); - - String pats = defineText.substring(fifthIndex + 1).trim(); - Matcher patMatcher = slashPattern.matcher(pats); - - String guardPattern = null; - - if(hasGuard) { - if(!patMatcher.find()) { - Errors.inst.printError(EK_CONS_INVDEFINE, "(no guard pattern)"); - return false; - } - - guardPattern = patMatcher.group(1); - } - - if(!patMatcher.find()) { - Errors.inst.printError(EK_CONS_INVDEFINE, "(no search pattern)"); - return false; - } - - String searchPattern = patMatcher.group(1); - List replacePatterns = new LinkedList<>(); - - while(patMatcher.find()) { - replacePatterns.add(patMatcher.group(1)); - } - - Define dfn = new Define(priority, subMode, doRecur, isCircular, - guardPattern, searchPattern, replacePatterns); - - if(dfn.inError) return false; - - if(type == Define.Type.LINE) { - eng.addLineDefine(dfn); - } else { - eng.addTokenDefine(dfn); - } - - return true; - } - - public static void main(String[] args) { - DiceLangConsole console = new DiceLangConsole(args); - - console.run(); - } -} diff --git a/dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java b/dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java deleted file mode 100644 index 8a877af..0000000 --- a/dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java +++ /dev/null @@ -1,551 +0,0 @@ -package bjc.dicelang.v2; - -import bjc.utils.data.IPair; -import bjc.utils.data.ITree; -import bjc.utils.data.Pair; -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 static bjc.dicelang.v2.Errors.ErrorKey.*; -import static bjc.dicelang.v2.Token.Type.*; - -import java.util.Comparator; -import java.util.Deque; -import java.util.Iterator; -import java.util.List; -import java.util.LinkedList; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class DiceLangEngine { - // Input rules for processing tokens - private List> opExpansionList; - private List> deaffixationList; - - // ID for generation - private int nextLiteral; - - // Debug indicator - private 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 postfixing - private Shunter shunt; - // Tokenizer for tokenizing - private Tokenizer tokenzer; - // Parser for tree construction - private Parser parsr; - // Evaluator for evaluating - private Evaluator eval; - - // Tables for symbols - public final IMap symTable; - public final IMap stringLits; - - - // Lists for preprocessing - private IList lineDefns; - private IList tokenDefns; - - // Are defns sorted by priority - private boolean defnsSorted; - - // Stream engine for processing streams - private StreamEngine streamEng; - - public DiceLangEngine() { - lineDefns = new FunctionalList<>(); - tokenDefns = new FunctionalList<>(); - defnsSorted = true; - - symTable = new FunctionalMap<>(); - stringLits = new FunctionalMap<>(); - - opExpansionList = new LinkedList<>(); - - opExpansionList.add(new Pair<>("+", "\\+")); - opExpansionList.add(new Pair<>("-", "-")); - opExpansionList.add(new Pair<>("*", "\\*")); - opExpansionList.add(new Pair<>("//", "//")); - opExpansionList.add(new Pair<>("/", "/")); - opExpansionList.add(new Pair<>(":=", ":=")); - opExpansionList.add(new Pair<>("=>", "=>")); - opExpansionList.add(new Pair<>(",", ",")); - - deaffixationList = new LinkedList<>(); - - deaffixationList.add(new Pair<>("(", "\\(")); - deaffixationList.add(new Pair<>(")", "\\)")); - deaffixationList.add(new Pair<>("[", "\\[")); - deaffixationList.add(new Pair<>("]", "\\]")); - deaffixationList.add(new Pair<>("{", "\\{")); - deaffixationList.add(new Pair<>("}", "}")); - - nextLiteral = 1; - - debugMode = true; - postfixMode = false; - prefixMode = false; - stepEval = false; - - streamEng = new StreamEngine(this); - shunt = new Shunter(); - tokenzer = new Tokenizer(this); - parsr = new Parser(); - eval = new Evaluator(this); - } - - public void sortDefns() { - Comparator defnCmp = (dfn1, dfn2) -> dfn1.priority - dfn2.priority; - - lineDefns.sort(defnCmp); - tokenDefns.sort(defnCmp); - - defnsSorted = true; - } - - public void addLineDefine(Define dfn) { - lineDefns.add(dfn); - - defnsSorted = false; - } - - public void addTokenDefine(Define dfn) { - tokenDefns.add(dfn); - - defnsSorted = false; - } - - public boolean toggleDebug() { - debugMode = !debugMode; - - return debugMode; - } - - public boolean togglePostfix() { - postfixMode = !postfixMode; - - return postfixMode; - } - - public boolean togglePrefix() { - prefixMode = !prefixMode; - - return prefixMode; - } - - public boolean toggleStepEval() { - stepEval = !stepEval; - - return stepEval; - } - - /* - * Matches quote-delimited strings - * (like "text" or "text\"text") - * Uses the "normal* (special normal*)*" pattern style - * recommended in 'Mastering regular expressions' - * Here, the normal is 'anything but a forward or backslash' - * (in regex, thats '[^\""]') and the special is 'an escaped forward slash' - * (in regex, thats '\\"') - * - * Then, we just follow the pattern, escape it for java strings, and - * add the enclosing quotes - */ - private Pattern quotePattern = Pattern.compile("\"([^\\\"]*(?:\\\"(?:[^\\\"])*)*)\""); - - // Similiar to the above, but using angle brackets instead of quotes - private Pattern nonExpandPattern = Pattern.compile("<<([^\\>]*(?:\\>(?:[^\\>])*)*)>>"); - - public boolean runCommand(String command) { - // Sort the defines if they aren't sorted - if(!defnsSorted) sortDefns(); - - IList streamToks = new FunctionalList<>(); - boolean success = streamEng.doStreams(command.split(" "), streamToks); - if(!success) return false; - - String newComm = ListUtils.collapseTokens(streamToks, " "); - - if(debugMode) - System.out.println("\tCommand after stream commands: " + newComm); - - for(Define dfn : lineDefns.toIterable()) { - newComm = dfn.apply(newComm); - } - - if(debugMode) - System.out.println("\tCommand after line defines: " + newComm); - - IMap stringLiterals = new FunctionalMap<>(); - - Matcher quoteMatcher = quotePattern.matcher(newComm); - StringBuffer destringedCommand = new StringBuffer(); - - while(quoteMatcher.find()) { - String stringLit = quoteMatcher.group(1); - - String litName = "stringLiteral" + nextLiteral++; - stringLiterals.put(litName, stringLit); - - quoteMatcher.appendReplacement(destringedCommand, " " + litName + " "); - } - - quoteMatcher.appendTail(destringedCommand); - - // Split the command into tokens - IList tokens = FunctionalStringTokenizer - .fromString(destringedCommand.toString()).toList(); - - if(debugMode) { - System.out.println("\tCommand after destringing: " + destringedCommand); - - if(stringLiterals.getSize() > 0) { - System.out.println("\tString literals in table"); - - stringLiterals.forEach((key, val) -> { - System.out.printf("\t\tName: (%s)\tValue: (%s)\n", key, val); - }); - } - } - - IMap nonExpandedTokens = new FunctionalMap<>(); - - tokens = tokens.map(tk -> { - Matcher nonExpandMatcher = nonExpandPattern.matcher(tk); - - if(nonExpandMatcher.matches()) { - String tkName = "nonExpandToken" + nextLiteral++; - nonExpandedTokens.put(tkName, nonExpandMatcher.group(1)); - - return tkName; - } else { - return tk; - } - }); - - System.out.println("\tCommand after removal of non-expanders: " + tokens.toString()); - - IList semiExpandedTokens = deaffixTokens(tokens, deaffixationList); - IList fullyExpandedTokens = deaffixTokens(semiExpandedTokens, opExpansionList); - - System.out.println("\tCommand after token expansion: " + fullyExpandedTokens.toString()); - - fullyExpandedTokens = fullyExpandedTokens.map(tk -> { - if(tk.startsWith("nonExpandToken")) { - return nonExpandedTokens.get(tk); - } else { - return tk; - } - }); - - if(debugMode) - System.out.printf("\tCommand after non-expander reinsertion: " - + fullyExpandedTokens.toString() + "\n"); - - - IList lexedTokens = new FunctionalList<>(); - - for(String token : fullyExpandedTokens) { - String newTok = token; - - for(Define dfn : tokenDefns.toIterable()) { - newTok = dfn.apply(newTok); - } - - Token tk = tokenzer.lexToken(token, stringLiterals); - - if(tk == null) continue; - else if(tk == Token.NIL_TOKEN) return false; - else lexedTokens.add(tk); - } - - if(debugMode) - System.out.printf("\tCommand after tokenization: %s\n", lexedTokens.toString()); - - IList shuntedTokens = lexedTokens; - - IList preparedTokens = new FunctionalList<>(); - boolean sc = removePreshuntTokens(lexedTokens, preparedTokens); - - if(!sc) return false; - - if(debugMode && !postfixMode) - System.out.printf("\tCommand after pre-shunter removal: %s\n", preparedTokens.toString()); - - if(!postfixMode && !prefixMode) { - shuntedTokens = new FunctionalList<>(); - success = shunt.shuntTokens(preparedTokens, shuntedTokens); - if(!success) return false; - } else if(prefixMode) { - preparedTokens.reverse(); - shuntedTokens = preparedTokens.map(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; - } - }); - } - - if(debugMode && !postfixMode) - System.out.printf("\tCommand after shunting: %s\n", shuntedTokens.toString()); - - IList readyTokens = shuntedTokens.flatMap(tk -> { - if(tk.type == Token.Type.TOKGROUP) { - return tk.tokenValues; - } else if(tk.type == Token.Type.TAGOP || tk.type == Token.Type.TAGOPR) { - return tk.tokenValues; - } else { - return new FunctionalList<>(tk); - } - }); - - if(debugMode && !postfixMode) - System.out.printf("\tCommand after re-preshunting: %s\n", readyTokens.toString()); - - IList> astForest = new FunctionalList<>(); - success = parsr.parseTokens(readyTokens, astForest); - - if(!success) return false; - - if(debugMode) { - evaluateForest(astForest); - } - - return true; - } - - private void evaluateForest(IList> astForest) { - System.out.println("\tParsed forest of asts"); - int treeNo = 1; - - for(ITree ast : astForest) { - System.out.println("\t\tTree " + treeNo + " in forest:\n" + ast); - - if(stepEval) { - int step = 1; - - for(Iterator> itr = eval.stepDebug(ast); itr.hasNext();){ - ITree nodeStep = itr.next(); - - System.out.printf("\t\tStep %d: Node is %s", step, nodeStep); - - if(nodeStep == null) { - System.out.println(); - - step += 1; - continue; - } - - if(nodeStep.getHead().type == Node.Type.RESULT) { - 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(")"); - } - - - System.out.println(); - step += 1; - } - } else { - EvaluatorResult res = eval.evaluate(ast); - 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; - } - } - - private boolean removePreshuntTokens(IList lexedTokens, IList preparedTokens) { - boolean success; - int curBraceCount = 0; - Deque> bracedTokens = new LinkedList<>(); - IList curBracedTokens = null; - - for(Token tk : lexedTokens) { - if(tk.type == Token.Type.OBRACE && tk.intValue == 2) { - curBraceCount += 1; - - if(curBraceCount != 1) { - bracedTokens.push(curBracedTokens); - } - - curBracedTokens = new FunctionalList<>(); - } else if(tk.type == Token.Type.CBRACE && tk.intValue == 2) { - if(curBraceCount == 0) { - Errors.inst.printError(EK_ENG_NOOPENING); - return false; - } - - curBraceCount -= 1; - - IList preshuntTokens = new FunctionalList<>(); - - success = shunt.shuntTokens(curBracedTokens, preshuntTokens); - - if(debugMode) - System.out.println("\t\tPreshunted " + curBracedTokens + " into " + preshuntTokens); - - if(!success) return false; - - if(curBraceCount >= 1) { - curBracedTokens = bracedTokens.pop(); - - curBracedTokens.add(new Token(Token.Type.TOKGROUP, preshuntTokens)); - } else { - preparedTokens.add(new Token(Token.Type.TOKGROUP, preshuntTokens)); - } - } else { - if(curBraceCount >= 1) { - curBracedTokens.add(tk); - } else { - preparedTokens.add(tk); - } - } - } - - if(curBraceCount > 0) { - Errors.inst.printError(EK_ENG_NOCLOSING); - return false; - } - - return true; - } - - - - private IList deaffixTokens(IList tokens, List> deaffixTokens) { - Deque working = new LinkedList<>(); - - for(String tk : tokens) { - working.add(tk); - } - - for(IPair op : deaffixTokens) { - Deque newWorking = new LinkedList<>(); - - String opRegex = op.getRight(); - - Pattern opRegexPattern = Pattern.compile(opRegex); - Pattern opRegexOnly = Pattern.compile("\\A(?:" + opRegex + ")+\\Z"); - Pattern opRegexStarting = Pattern.compile("\\A" + opRegex); - Pattern opRegexEnding = Pattern.compile(opRegex + "\\Z"); - - for(String tk : working) { - if(opRegexOnly.matcher(tk).matches()) { - // The string contains only the operator - newWorking.add(tk); - } else { - Matcher medianMatcher = opRegexPattern.matcher(tk); - - // Read the first match - boolean found = medianMatcher.find(); - - if(!found) { - newWorking.add(tk); - continue; - } - - Matcher startMatcher = opRegexStarting.matcher(tk); - Matcher endMatcher = opRegexEnding.matcher(tk); - - boolean startsWith = startMatcher.find(); - boolean endsWith = endMatcher.find(); - boolean doSplit = medianMatcher.find(); - - medianMatcher.reset(); - - if(doSplit || (!startsWith && !endsWith)) { - String[] pieces = opRegexPattern.split(tk); - - if(startsWith) { - // Skip the starting operator - medianMatcher.find(); - newWorking.add(tk.substring(0, startMatcher.end())); - } - - for(int i = 0; i < pieces.length; i++) { - String piece = pieces[i]; - - // Find the next operator - boolean didFind = medianMatcher.find(); - - if(piece.equals("")) { - System.out.printf("\tWARNING: Empty token found during operator expansion" - + "of token (%s). Weirdness may happen as a result\n", tk); - continue; - } - - newWorking.add(piece); - - if(didFind) - newWorking.add(tk.substring(medianMatcher.start(), medianMatcher.end())); - } - - if(endsWith) - newWorking.add(tk.substring(endMatcher.start())); - } else if(startsWith && endsWith) { - newWorking.add(tk.substring(0, startMatcher.end())); - newWorking.add(tk.substring(startMatcher.end(), endMatcher.start())); - newWorking.add(tk.substring(endMatcher.start())); - } else if(startsWith) { - newWorking.add(tk.substring(0, startMatcher.end())); - newWorking.add(tk.substring(startMatcher.end())); - } else if(endsWith) { - newWorking.add(tk.substring(0, endMatcher.start())); - newWorking.add(tk.substring(endMatcher.start())); - } else { - newWorking.add(tk); - } - } - - } - - working = newWorking; - } - - IList returned = new FunctionalList<>(); - for(String ent : working) { - returned.add(ent); - } - - return returned; - } -} diff --git a/dice-lang/src/bjc/dicelang/v2/DoubleMatcher.java b/dice-lang/src/bjc/dicelang/v2/DoubleMatcher.java deleted file mode 100644 index 5f6f0db..0000000 --- a/dice-lang/src/bjc/dicelang/v2/DoubleMatcher.java +++ /dev/null @@ -1,58 +0,0 @@ -package bjc.dicelang.v2; - -import java.util.regex.Pattern; - -/** - * Checks if a string would pass Double.parseDouble. - * - * Uses a regex from the javadoc for Double.valueOf() - */ -public class DoubleMatcher { - private static final String Digits = - "(\\p{Digit}+)"; - private static final String HexDigits = - "(\\p{XDigit}+)"; - - // an exponent is 'e' or 'E' followed by an optionally - // signed decimal integer. - private static final String Exp = - "[eE][+-]?" + Digits; - - private static final String fpRegex = - ("[\\x00-\\x20]*" + - // Optional leading "whitespace" - "[+-]?(" + // Optional sign character - "NaN|" + // "NaN" string - "Infinity|" + // "Infinity" string - - // A decimal floating-point string representing a finite positive - // number without a leading sign has at most five basic pieces: - // Digits . Digits ExponentPart FloatTypeSuffix - // - // Since this method allows integer-only strings as input - // in addition to strings of floating-point literals, the - // two sub-patterns below are simplifications of the grammar - // productions from section 3.10.2 of - // The Java™ Language Specification. - - // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt - "((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+ - - // . Digits ExponentPart_opt FloatTypeSuffix_opt - "(\\.("+Digits+")("+Exp+")?)|"+ - - // Hexadecimal strings - "((" + - // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt - "(0[xX]" + HexDigits + "(\\.)?)|" + - - // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt - "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" + - - ")[pP][+-]?" + Digits + "))" + - "[fFdD]?))" + - "[\\x00-\\x20]*");// Optional trailing "whitespace" - - public static final Pattern floatingLiteral = Pattern.compile("\\A" + fpRegex + "\\Z"); - -} diff --git a/dice-lang/src/bjc/dicelang/v2/Errors.java b/dice-lang/src/bjc/dicelang/v2/Errors.java deleted file mode 100644 index 6ad74ab..0000000 --- a/dice-lang/src/bjc/dicelang/v2/Errors.java +++ /dev/null @@ -1,245 +0,0 @@ -package bjc.dicelang.v2; - -public class Errors { - public static enum ErrorKey { - // Define Errors - // Incorrect define guard syntax - EK_DFN_PREDSYN, - // Incorrect define search syntax - EK_DFN_SRCSYN, - // Recursive define recursed too many times - EK_DFN_RECUR, - - // Console Errors - // Unknown console pragma - EK_CONS_INVPRAG, - // Improperly formatted define - EK_CONS_INVDEFINE, - - // Language Engine Errors - // Found closing doublebrace w/out opening doublebrace - EK_ENG_NOOPENING, - // Reached end of command w/out balanced doublebraces - EK_ENG_NOCLOSING, - - // Tokenizer Errors - // Found an unexpected grouping token - EK_TOK_UNGROUP, - // Invalid base for a flexadecimal number - EK_TOK_INVBASE, - // Invalid flexadecimal number in a given base - EK_TOK_INVFLEX, - - // Evaluator Errors - // Unknown node type - EK_EVAL_INVNODE, - // Incorrect # of args to binary operator - EK_EVAL_INVBIN, - // Incorrect # of args to unary operator - EK_EVAL_INVUNARY, - // Unknown binary operator - EK_EVAL_UNBIN, - // Unknown unary operator - EK_EVAL_UNUNARY, - // Math on strings doesn't work - EK_EVAL_STRINGMATH, - // Attempted divide by zero - EK_EVAL_DIVZERO, - // Attempted to divide dice - EK_EVAL_DIVDICE, - // Unknown math operator - EK_EVAL_UNMATH, - // Unknown token reference - EK_EVAL_UNTOK, - // Unknown dice operator - EK_EVAL_UNDICE, - // Incorrect type to dice group operator - EK_EVAL_INVDGROUP, - // Incorrect type to other dice operator - EK_EVAL_INVDICE, - // Mismatched types to math operator - EK_EVAL_MISMATH, - - // Parser Error - // Group closing where there couldn't be an opener - EK_PARSE_NOCLOSE, - // Group closing without group opener - EK_PARSE_UNCLOSE, - // Incorrect # of arguments to binary operator - EK_PARSE_BINARY, - // Not enough operands to binary operator - EK_PARSE_UNOPERAND, - // Unrecognized token type - EK_PARSE_INVTOKEN, - - // Shunter Error - // Unary operator expected a operand, but got an operator - EK_SHUNT_NOTADV, - // Unary operator expected an operator, but got an operand - EK_SHUNT_NOTADJ, - // Unary operator expected an operator, but didn't find one - EK_SHUNT_NOOP, - // Asked for opening grouping operator, but couldn't find one - EK_SHUNT_NOGROUP, - // No group for group seperator to attach to - EK_SHUNT_INVSEP, - - // Stream Errors - // Attempted to switch to a non-existant stream - EK_STRM_NONEX, - // Can't delete the last stream - EK_STRM_LAST, - // Unknown stream command - EK_STRM_INVCOM, - - } - - public static enum ErrorMode { - WIZARD, DEV - } - - private ErrorMode mode; - - public void printError(ErrorKey key, String... args) { - switch(mode) { - case WIZARD: - System.out.println("\t? " + key.ordinal()); - break; - case DEV: - devError(key, args); - break; - default: - System.out.println("\tERROR ERROR: Unknown error mode " + mode); - } - } - - private void devError(ErrorKey key, String[] args) { - switch(key) { - case EK_DFN_PREDSYN: - System.out.printf("\tERROR: Incorrect define guard syntax %s\n", args[0]); - break; - case EK_DFN_SRCSYN: - System.out.printf("\tERROR: Incorrect define match syntax %s\n", args[0]); - break; - case EK_DFN_RECUR: - System.out.printf("\tERROR: Recursive define didn't converge after %s iterations." - + " Original string was %s, last iteration was %s\n", - args[0], args[1], args[2]); - break; - case EK_CONS_INVPRAG: - System.out.printf("\tERROR: Unknown pragma %s\n", args[0]); - break; - case EK_CONS_INVDEFINE: - System.out.printf("\tERROR: Improperly formatted define %s\n", args[0]); - break; - case EK_ENG_NOOPENING: - System.out.printf("\tERROR: Encountered closing doublebrace without" - + " matching opening doublebrace\n"); - break; - case EK_ENG_NOCLOSING: - System.out.printf("\tERROR: Reached end of string before closing doublebrace was found\n"); - break; - case EK_TOK_UNGROUP: - System.out.printf("\tERROR: Unrecognized grouping token %s\n", args[0]); - break; - case EK_TOK_INVBASE: - System.out.printf("\tERROR: Invalid flexadecimal base %s\n", args[0]); - break; - case EK_TOK_INVFLEX: - System.out.printf("\tERROR: Invalid flexadecimal number %s in base %s\n", args[0], args[1]); - break; - case EK_EVAL_INVNODE: - System.out.printf("\tERROR: Unknown node in evaluator: %s\n", args[0]); - break; - case EK_EVAL_INVBIN: - System.out.printf("\tERROR: Binary operators take 2 operand, not %s\n" - + "\tProblem node is %s\n", args[0], args[1]); - break; - case EK_EVAL_UNBIN: - System.out.printf("\tERROR: Unknown binary operator %s\n", args[0]); - break; - case EK_EVAL_STRINGMATH: - System.out.printf("\tERROR: Math operators don't work on strings\n"); - break; - case EK_EVAL_DIVZERO: - System.out.printf("\tERROR: Attempted divide by zero\n"); - break; - case EK_EVAL_DIVDICE: - System.out.printf("\tERROR: Dice cannot be divided\n"); - break; - case EK_EVAL_UNMATH: - System.out.printf("\tERROR: Unknown math binary operator: %s\n", args[0]); - break; - case EK_EVAL_UNTOK: - System.out.printf("\tERROR: Unknown token ref %s\n", args[0]); - break; - case EK_EVAL_UNDICE: - System.out.printf("\tERROR: Unknown dice operator %s\n", args[0]); - break; - case EK_EVAL_INVDGROUP: - System.out.printf("\tERROR: Dice group operator expects scalar dice or integers," - + " not %s\n", args[0]); - break; - case EK_EVAL_INVDICE: - System.out.printf("\tERROR: Dice operators expect scalar dice, not %s\n", args[0]); - break; - case EK_EVAL_MISMATH: - System.out.printf("\tERROR: Math operators expect two operands of the same type\n"); - break; - case EK_PARSE_NOCLOSE: - System.out.printf("\tERROR: Group closing with no possible group opener\n"); - break; - case EK_PARSE_UNCLOSE: - System.out.printf("\tERROR: Found group closer without opener: (closing was %s" - + ", expected %s)\n", args[0], args[1]); - break; - case EK_PARSE_BINARY: - System.out.printf("\tERROR: Expected at least two operands\n"); - break; - case EK_PARSE_UNOPERAND: - System.out.printf("\tERROR: Operator %s expected more operands than provided\n", args[0]); - break; - case EK_PARSE_INVTOKEN: - System.out.printf("\tERROR: Unrecognized token type in parsing: %s\n", args[0]); - break; - case EK_SHUNT_NOTADV: - System.out.printf("\tERROR: Unary operator %s is an adjective, not an adverb. It can't be" - + " applied to the operator %s\n", args[0], args[1]); - break; - case EK_SHUNT_NOTADJ: - System.out.printf("\tERROR: Unary operator %s is an adjective, not an adverb. It can't be" - + " applied to the operator %s\n", args[0], args[1]); - break; - case EK_SHUNT_NOOP: - System.out.printf("\tERROR: Unary operator %s is an adverb, but there is no operator" - + " to apply it to\n", args[0]); - break; - case EK_SHUNT_NOGROUP: - System.out.printf("\tERROR: Couldn't find matching grouping %s (expected %s)\n", - args[0], args[1]); - break; - case EK_SHUNT_INVSEP: - System.out.printf("\tERROR: Couldn't find grouper for group seperator to attach to\n"); - break; - case EK_STRM_NONEX: - System.out.printf("\tERROR: Attempted to switch to non-existent stream\n"); - break; - case EK_STRM_LAST: - System.out.printf("\tERROR: Cannot delete last stream\n"); - break; - case EK_STRM_INVCOM: - System.out.printf("\tERROR: Unknown stream control command %s\n", args[0]); - break; - default: - System.out.printf("\tERROR ERROR: Unknown error key %s\n", key); - } - } - - public final static Errors inst; - - static { - inst = new Errors(); - - inst.mode = ErrorMode.DEV; - } -} diff --git a/dice-lang/src/bjc/dicelang/v2/Evaluator.java b/dice-lang/src/bjc/dicelang/v2/Evaluator.java deleted file mode 100644 index ed9db17..0000000 --- a/dice-lang/src/bjc/dicelang/v2/Evaluator.java +++ /dev/null @@ -1,424 +0,0 @@ -package bjc.dicelang.v2; - -import bjc.dicelang.v2.dice.CompoundDie; -import bjc.dicelang.v2.dice.MathDie; -import bjc.dicelang.v2.dice.SimpleDie; -import bjc.dicelang.v2.dice.SimpleDieList; -import bjc.utils.data.ITree; -import bjc.utils.data.SingleIterator; -import bjc.utils.data.Tree; -import bjc.utils.data.TopDownTransformIterator; -import bjc.utils.data.TopDownTransformResult; - -import static bjc.dicelang.v2.Errors.ErrorKey.*; -import static bjc.dicelang.v2.EvaluatorResult.Type.*; - -import java.util.Deque; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.function.Consumer; - -public class Evaluator { - private static enum CoerceSteps { - INTEGER, FLOAT; - } - - private static class Context { - public Consumer>> thunk; - - public boolean isDebug; - } - - private static Node FAIL() { - return new Node(Node.Type.RESULT, new EvaluatorResult(FAILURE)); - } - - private static Node FAIL(ITree orig) { - return new Node(Node.Type.RESULT, new EvaluatorResult(FAILURE, orig)); - } - - private static Node FAIL(Node orig) { - return new Node(Node.Type.RESULT, new EvaluatorResult(FAILURE, orig)); - } - - private static Node FAIL(EvaluatorResult res) { - return new Node(Node.Type.RESULT, new EvaluatorResult(FAILURE, new Node(Node.Type.RESULT, res))); - } - - private DiceLangEngine eng; - - public Evaluator(DiceLangEngine en) { - eng = en; - } - - public EvaluatorResult evaluate(ITree comm) { - Context ctx = new Context(); - - ctx.isDebug = false; - ctx.thunk = (itr) -> { - // Deliberately finish the iterator, but ignore results. It's only for stepwise evaluation - // but we don't know if stepping the iterator causes something to happen - while(itr.hasNext()) itr.next(); - }; - - return comm.topDownTransform(this::pickEvaluationType, - (node) -> this.evaluateNode(node, ctx)).getHead().resultVal; - } - - // @FIXME Something's broken with step evaluation - public Iterator> stepDebug(ITree comm) { - Context ctx = new Context(); - - ctx.isDebug = true; - - return new TopDownTransformIterator<>(this::pickEvaluationType, (node, thnk) -> { - ctx.thunk = thnk; - - return this.evaluateNode(node, ctx); - }, comm); - } - - private TopDownTransformResult pickEvaluationType(Node nd) { - switch(nd.type) { - case UNARYOP: - switch(nd.operatorType) { - case COERCE: - return TopDownTransformResult.RTRANSFORM; - default: - return TopDownTransformResult.PUSHDOWN; - } - default: - return TopDownTransformResult.PUSHDOWN; - } - } - - private ITree evaluateNode(ITree ast, Context ctx) { - switch(ast.getHead().type) { - case UNARYOP: - return evaluateUnaryOp(ast, ctx); - case BINOP: - return evaluateBinaryOp(ast, ctx); - case TOKREF: - return evaluateTokenRef(ast.getHead().tokenVal, ctx); - case ROOT: - return ast.getChild(ast.getChildrenCount() - 1); - case RESULT: - return ast; - default: - Errors.inst.printError(EK_EVAL_INVNODE, ast.getHead().type.toString()); - return new Tree<>(FAIL(ast)); - } - } - - private ITree evaluateUnaryOp(ITree ast, Context ctx) { - switch(ast.getHead().operatorType) { - case COERCE: - if(ast.getChildrenCount() != 1) { - Errors.inst.printError(EK_EVAL_UNUNARY, Integer.toString(ast.getChildrenCount())); - return new Tree<>(FAIL(ast)); - } - - ITree toCoerce = ast.getChild(0); - ITree retVal = new Tree<>(toCoerce.getHead()); - Deque> children = new LinkedList<>(); - - CoerceSteps curLevel = CoerceSteps.INTEGER; - - for(int i = 0; i < toCoerce.getChildrenCount(); i++) { - ITree child = toCoerce.getChild(i); - ITree nChild = null; - - if(ctx.isDebug) { - Iterator> nd = stepDebug(child); - - for(; nd.hasNext(); nChild = nd.next()) { - ctx.thunk.accept(new SingleIterator<>(child)); - } - } else { - nChild = new Tree<>(new Node(Node.Type.RESULT, evaluate(child))); - - if(nChild != null) ctx.thunk.accept(new SingleIterator<>(nChild)); - } - - Node childNode = nChild.getHead(); - EvaluatorResult res = childNode.resultVal; - - if(res.type == FLOAT) curLevel = CoerceSteps.FLOAT; - - children.add(nChild); - } - - for(ITree child : children) { - Node nd = child.getHead(); - EvaluatorResult res = nd.resultVal; - - switch(res.type) { - case INT: - if(curLevel == CoerceSteps.FLOAT) { - nd.resultVal = new EvaluatorResult(FLOAT, (double)res.intVal); - } - default: - // Do nothing - break; - } - - retVal.addChild(child); - } - - return retVal; - default: - Errors.inst.printError(EK_EVAL_INVUNARY, ast.getHead().operatorType.toString()); - return new Tree<>(FAIL(ast)); - } - } - - private ITree evaluateBinaryOp(ITree ast, Context ctx) { - Token.Type binOp = ast.getHead().operatorType; - - if(ast.getChildrenCount() != 2) { - Errors.inst.printError(EK_EVAL_INVBIN, Integer.toString(ast.getChildrenCount()), ast.toString()); - - return new Tree<>(FAIL(ast)); - } - - ITree left = ast.getChild(0); - ITree right = ast.getChild(1); - - switch(binOp) { - case ADD: - case SUBTRACT: - case MULTIPLY: - case DIVIDE: - case IDIVIDE: - return evaluateMathBinary(binOp, - left.getHead().resultVal, right.getHead().resultVal, - ctx); - case DICEGROUP: - case DICECONCAT: - case DICELIST: - return evaluateDiceBinary(binOp, - left.getHead().resultVal, right.getHead().resultVal, - ctx); - default: - Errors.inst.printError(EK_EVAL_UNBIN, binOp.toString()); - return new Tree<>(FAIL(ast)); - } - } - - private ITree evaluateDiceBinary(Token.Type op, - EvaluatorResult left, EvaluatorResult right, Context ctx) { - EvaluatorResult res = null; - - switch(op) { - case DICEGROUP: - if(left.type == DICE && !left.diceVal.isList) { - if(right.type == DICE && !right.diceVal.isList) { - res = new EvaluatorResult(DICE, - new SimpleDie(left.diceVal.scalar, right.diceVal.scalar)); - } else if (right.type == INT) { - res = new EvaluatorResult(DICE, new SimpleDie(left.diceVal.scalar, right.intVal)); - } else { - Errors.inst.printError(EK_EVAL_INVDGROUP, right.type.toString()); - return new Tree<>(FAIL(right)); - } - } else if(left.type == INT) { - if(right.type == DICE && !right.diceVal.isList) { - res = new EvaluatorResult(DICE, new SimpleDie(left.intVal, right.diceVal.scalar)); - } else if (right.type == INT) { - res = new EvaluatorResult(DICE, new SimpleDie(left.intVal, right.intVal)); - } else { - Errors.inst.printError(EK_EVAL_INVDGROUP, right.type.toString()); - return new Tree<>(FAIL(right)); - } - } else { - Errors.inst.printError(EK_EVAL_INVDGROUP, left.type.toString()); - return new Tree<>(FAIL(left)); - } - case DICECONCAT: - if(left.type != DICE || left.diceVal.isList) { - Errors.inst.printError(EK_EVAL_INVDICE, left.type.toString()); - return new Tree<>(FAIL(left)); - } else if(right.type != DICE || right.diceVal.isList) { - Errors.inst.printError(EK_EVAL_INVDICE, right.type.toString()); - return new Tree<>(FAIL(right)); - } else { - res = new EvaluatorResult(DICE, - new CompoundDie(left.diceVal.scalar, right.diceVal.scalar)); - } - break; - case DICELIST: - if(left.type != DICE || left.diceVal.isList) { - Errors.inst.printError(EK_EVAL_INVDICE, left.type.toString()); - return new Tree<>(FAIL(left)); - } else if(right.type != DICE || right.diceVal.isList) { - Errors.inst.printError(EK_EVAL_INVDICE, right.type.toString()); - return new Tree<>(FAIL(right)); - } else { - res = new EvaluatorResult(DICE, - new SimpleDieList(left.diceVal.scalar, right.diceVal.scalar)); - } - break; - default: - Errors.inst.printError(EK_EVAL_UNDICE, op.toString()); - return new Tree<>(FAIL()); - } - - return new Tree<>(new Node(Node.Type.RESULT, res)); - } - - private ITree evaluateMathBinary(Token.Type op, - EvaluatorResult left, EvaluatorResult right, Context ctx) { - if(left.type == STRING || right.type == STRING) { - Errors.inst.printError(EK_EVAL_STRINGMATH); - return new Tree<>(FAIL()); - } else if(left.type == FAILURE || right.type == FAILURE) { - return new Tree<>(FAIL()); - } else if(left.type == INT && right.type != INT) { - Errors.inst.printError(EK_EVAL_MISMATH); - return new Tree<>(FAIL(right)); - } else if(left.type == FLOAT && right.type != FLOAT) { - Errors.inst.printError(EK_EVAL_MISMATH); - return new Tree<>(FAIL(right)); - } else if(left.type == DICE && right.type != DICE) { - Errors.inst.printError(EK_EVAL_MISMATH); - return new Tree<>(FAIL(right)); - } else if(right.type == INT && left.type != INT) { - Errors.inst.printError(EK_EVAL_MISMATH); - return new Tree<>(FAIL(left)); - } else if(right.type == FLOAT && left.type != FLOAT) { - Errors.inst.printError(EK_EVAL_MISMATH); - return new Tree<>(FAIL(left)); - } else if(right.type == DICE && left.type != DICE) { - Errors.inst.printError(EK_EVAL_MISMATH); - return new Tree<>(FAIL(left)); - } - - EvaluatorResult res = null; - - switch(op) { - case ADD: - if(left.type == INT) { - res = new EvaluatorResult(INT, left.intVal + right.intVal); - } else if(left.type == DICE) { - if(left.diceVal.isList) { - Errors.inst.printError(EK_EVAL_INVDICE, left.toString()); - return new Tree<>(FAIL(left)); - } else if(right.diceVal.isList) { - Errors.inst.printError(EK_EVAL_INVDICE, right.toString()); - return new Tree<>(FAIL(right)); - } - - res = new EvaluatorResult(DICE, new MathDie(MathDie.MathOp.ADD, - left.diceVal.scalar, right.diceVal.scalar)); - } else { - res = new EvaluatorResult(FLOAT, left.floatVal + right.floatVal); - } - break; - case SUBTRACT: - if(left.type == INT) { - res = new EvaluatorResult(INT, left.intVal - right.intVal); - } else if(left.type == DICE) { - if(left.diceVal.isList) { - Errors.inst.printError(EK_EVAL_INVDICE, left.toString()); - return new Tree<>(FAIL(left)); - } else if(right.diceVal.isList) { - Errors.inst.printError(EK_EVAL_INVDICE, right.toString()); - return new Tree<>(FAIL(right)); - } - - res = new EvaluatorResult(DICE, new MathDie(MathDie.MathOp.SUBTRACT, - left.diceVal.scalar, right.diceVal.scalar)); - } else { - res = new EvaluatorResult(FLOAT, left.floatVal - right.floatVal); - } - break; - case MULTIPLY: - if(left.type == INT) { - res = new EvaluatorResult(INT, left.intVal * right.intVal); - } else if(left.type == DICE) { - if(left.diceVal.isList) { - Errors.inst.printError(EK_EVAL_INVDICE, left.toString()); - return new Tree<>(FAIL(left)); - } else if(right.diceVal.isList) { - Errors.inst.printError(EK_EVAL_INVDICE, right.toString()); - return new Tree<>(FAIL(right)); - } - - res = new EvaluatorResult(DICE, new MathDie(MathDie.MathOp.MULTIPLY, - left.diceVal.scalar, right.diceVal.scalar)); - } else { - res = new EvaluatorResult(FLOAT, left.floatVal * right.floatVal); - } - break; - case DIVIDE: - if(left.type == INT) { - if(right.intVal == 0) { - Errors.inst.printError(EK_EVAL_DIVZERO); - res = new EvaluatorResult(FAILURE, right); - } else { - res = new EvaluatorResult(FLOAT, left.intVal / right.intVal); - } - } else if(left.type == FLOAT) { - if(right.floatVal == 0) { - Errors.inst.printError(EK_EVAL_DIVZERO); - res = new EvaluatorResult(FAILURE, right); - } else { - res = new EvaluatorResult(FLOAT, left.floatVal / right.floatVal); - } - } else { - Errors.inst.printError(EK_EVAL_DIVDICE); - return new Tree<>(FAIL()); - } - break; - case IDIVIDE: - if(left.type == INT) { - if(right.intVal == 0) { - Errors.inst.printError(EK_EVAL_DIVZERO); - res = new EvaluatorResult(FAILURE, right); - } else { - res = new EvaluatorResult(INT, (int) (left.intVal / right.intVal)); - } - } else if(left.type == FLOAT) { - if(right.floatVal == 0) { - Errors.inst.printError(EK_EVAL_DIVZERO); - res = new EvaluatorResult(FAILURE, right); - } else { - res = new EvaluatorResult(INT, (int) (left.floatVal / right.floatVal)); - } - } else { - Errors.inst.printError(EK_EVAL_DIVDICE); - return new Tree<>(FAIL()); - } - break; - default: - Errors.inst.printError(EK_EVAL_UNMATH, op.toString()); - return new Tree<>(FAIL()); - } - - return new Tree<>(new Node(Node.Type.RESULT, res)); - } - - private ITree evaluateTokenRef(Token tk, Context ctx) { - EvaluatorResult res = null; - - switch(tk.type) { - case INT_LIT: - res = new EvaluatorResult(INT, tk.intValue); - break; - case FLOAT_LIT: - res = new EvaluatorResult(FLOAT, tk.floatValue); - break; - case DICE_LIT: - res = new EvaluatorResult(DICE, tk.diceValue); - break; - case STRING_LIT: - res = new EvaluatorResult(STRING, eng.stringLits.get((int)(tk.intValue))); - break; - default: - Errors.inst.printError(EK_EVAL_UNTOK, tk.type.toString()); - res = new EvaluatorResult(FAILURE); - } - - return new Tree<>(new Node(Node.Type.RESULT, res)); - } -} diff --git a/dice-lang/src/bjc/dicelang/v2/EvaluatorResult.java b/dice-lang/src/bjc/dicelang/v2/EvaluatorResult.java deleted file mode 100644 index bac4d2d..0000000 --- a/dice-lang/src/bjc/dicelang/v2/EvaluatorResult.java +++ /dev/null @@ -1,97 +0,0 @@ -package bjc.dicelang.v2; - -import bjc.dicelang.v2.dice.Die; -import bjc.dicelang.v2.dice.DieExpression; -import bjc.dicelang.v2.dice.DieList; -import bjc.utils.data.ITree; -import bjc.utils.data.Tree; - -public class EvaluatorResult { - public static enum Type { - FAILURE, - INT, FLOAT, DICE, STRING - } - - public final EvaluatorResult.Type type; - - // These may or may not have values based - // off of the result type - public long intVal; - public double floatVal; - public DieExpression diceVal; - public String stringVal; - - // Original node data - public ITree origVal; - - public EvaluatorResult(EvaluatorResult.Type typ) { - type = typ; - } - - public EvaluatorResult(EvaluatorResult.Type typ, ITree orig) { - this(typ); - - origVal = orig; - } - - public EvaluatorResult(EvaluatorResult.Type typ, Node orig) { - this(typ, new Tree<>(orig)); - } - - public EvaluatorResult(EvaluatorResult.Type typ, EvaluatorResult orig) { - this(typ, new Node(Node.Type.RESULT, orig)); - } - - public EvaluatorResult(EvaluatorResult.Type typ, long iVal) { - this(typ); - - intVal = iVal; - } - - public EvaluatorResult(EvaluatorResult.Type typ, double dVal) { - this(typ); - - floatVal = dVal; - } - - public EvaluatorResult(EvaluatorResult.Type typ, DieExpression dVal) { - this(typ); - - diceVal = dVal; - } - - public EvaluatorResult(EvaluatorResult.Type typ, Die dVal) { - this(typ); - - diceVal = new DieExpression(dVal); - } - - public EvaluatorResult(EvaluatorResult.Type typ, DieList dVal) { - this(typ); - - diceVal = new DieExpression(dVal); - } - - public EvaluatorResult(EvaluatorResult.Type typ, String strang) { - this(typ); - - stringVal = strang; - } - - public String toString() { - switch(type) { - case INT: - return type.toString() + "(" + intVal + ")"; - case FLOAT: - return type.toString() + "(" + floatVal + ")"; - case DICE: - return type.toString() + "(" + diceVal + ")"; - case STRING: - return type.toString() + "(" + stringVal + ")"; - case FAILURE: - return type.toString(); - default: - return "Unknown result type " + type.toString(); - } - } -} \ No newline at end of file diff --git a/dice-lang/src/bjc/dicelang/v2/Node.java b/dice-lang/src/bjc/dicelang/v2/Node.java deleted file mode 100644 index 334a9f3..0000000 --- a/dice-lang/src/bjc/dicelang/v2/Node.java +++ /dev/null @@ -1,82 +0,0 @@ -package bjc.dicelang.v2; - -public class Node { - public static enum Type { - ROOT, TOKREF, - UNARYOP, BINOP, - GROUP, OGROUP, - RESULT - } - - public static enum GroupType { - ARRAY, CODE - } - - public final Type type; - - // These can have or not have values based of the node type - public Token tokenVal; - public Token.Type operatorType; - public GroupType groupType; - public EvaluatorResult resultVal; - - public Node(Type typ) { - type = typ; - } - - public Node(Type typ, Token tokenVl) { - this(typ); - - tokenVal = tokenVl; - } - - public Node(Type typ, Token.Type opType) { - this(typ); - - operatorType = opType; - } - - public Node(Type typ, GroupType grupType) { - this(typ); - - groupType = grupType; - } - - public Node(Type typ, EvaluatorResult res) { - this(typ); - - resultVal = res; - } - - public String toString() { - switch(type) { - case UNARYOP: - case BINOP: - return "(" + type.name() + " : " + operatorType + ")"; - case OGROUP: - case TOKREF: - return "(" + type.name() + " : " + tokenVal + ")"; - case GROUP: - return "(" + type.name() + " : " + groupType + ")"; - case RESULT: - return "(" + type.name() + " : " + resultVal + ")"; - default: - return "Unknown node type " + type; - } - } - - public boolean equals(Object other) { - if(!(other instanceof Node)) return false; - - Node otk = (Node)other; - - if(otk.type != type) return false; - - switch(type) { - case OGROUP: - return tokenVal.equals(otk.tokenVal); - default: - return true; - } - } -} diff --git a/dice-lang/src/bjc/dicelang/v2/Parser.java b/dice-lang/src/bjc/dicelang/v2/Parser.java deleted file mode 100644 index a47707d..0000000 --- a/dice-lang/src/bjc/dicelang/v2/Parser.java +++ /dev/null @@ -1,167 +0,0 @@ -package bjc.dicelang.v2; - -import static bjc.dicelang.v2.Errors.ErrorKey.*; -import static bjc.dicelang.v2.Node.Type.*; -import static bjc.dicelang.v2.Token.Type.*; - -import java.util.Deque; -import java.util.LinkedList; - -import bjc.utils.data.ITree; -import bjc.utils.data.Tree; -import bjc.utils.funcdata.IList; - -public class Parser { - public Parser() { - - } - - public boolean parseTokens(IList tokens, - IList> results) { - Deque> working = new LinkedList<>(); - - for(Token tk : tokens) { - switch(tk.type) { - case OBRACKET: - case OBRACE: - working.push(new Tree<>(new Node(OGROUP, tk))); - break; - case CBRACKET: - case CBRACE: - boolean sc = parseClosingGrouper(working, tk); - if(!sc) return false; - break; - case LET: - case BIND: - if(working.size() < 2) { - Errors.inst.printError(EK_PARSE_BINARY); - return false; - } else { - ITree right = working.pop(); - ITree left = working.pop(); - - ITree opNode = new Tree<>(new Node(BINOP, tk.type)); - - working.push(opNode); - } - break; - case ADD: - case SUBTRACT: - case MULTIPLY: - case DIVIDE: - case IDIVIDE: - case DICEGROUP: - case DICECONCAT: - case DICELIST: - if(working.size() == 0) { - Errors.inst.printError(EK_PARSE_UNOPERAND, tk.toString()); - return false; - } else if(working.size() == 1) { - ITree operand = working.pop(); - - ITree opNode = new Tree<>(new Node(UNARYOP, tk.type)); - - opNode.addChild(operand); - - working.push(opNode); - } else { - ITree right = working.pop(); - ITree left = working.pop(); - - ITree opNode = new Tree<>(new Node(BINOP, tk.type)); - - opNode.addChild(left); - opNode.addChild(right); - - working.push(opNode); - } - break; - case COERCE: - if(working.size() == 0) { - Errors.inst.printError(EK_PARSE_UNOPERAND, tk.toString()); - } else { - ITree operand = working.pop(); - ITree opNode = new Tree<>(new Node(UNARYOP, tk.type)); - - opNode.addChild(operand); - - working.push(opNode); - } - break; - case INT_LIT: - case FLOAT_LIT: - case STRING_LIT: - case VREF: - case DICE_LIT: - working.push(new Tree<>(new Node(TOKREF, tk))); - break; - default: - Errors.inst.printError(EK_PARSE_INVTOKEN, tk.type.toString()); - return false; - } - } - - for(ITree ast : working) { - results.add(ast); - } - - return true; - } - - private boolean parseClosingGrouper(Deque> working, Token tk) { - if(working.size() == 0) { - Errors.inst.printError(EK_PARSE_NOCLOSE); - return false; - } - - ITree groupNode = null; - switch(tk.type) { - case CBRACE: - groupNode = new Tree<>(new Node(GROUP, Node.GroupType.CODE)); - break; - case CBRACKET: - groupNode = new Tree<>(new Node(GROUP, Node.GroupType.ARRAY)); - break; - default: - break; - } - - Token matching = null; - if(tk.type == CBRACKET) { - matching = new Token(Token.Type.OBRACKET, tk.intValue); - } else if(tk.type == CBRACE) { - matching = new Token(Token.Type.OBRACE, tk.intValue); - } - - ITree matchNode = new Tree<>(new Node(OGROUP, matching)); - if(!working.contains(matchNode)) { - Errors.inst.printError(EK_PARSE_UNCLOSE, tk.toString(), matchNode.toString()); - - System.out.println("\tCurrent forest is: "); - - int treeNo = 1; - for(ITree ast : working) { - System.out.println("Tree " + treeNo++ + ": " + ast.toString()); - } - - return false; - } else { - Deque> childs = new LinkedList<>(); - - while(!working.peek().equals(matchNode)) { - childs.push(working.pop()); - } - - // Discard opener - working.pop(); - - for(ITree child : childs) { - groupNode.addChild(child); - } - - working.push(groupNode); - } - - return true; - } -} diff --git a/dice-lang/src/bjc/dicelang/v2/Shunter.java b/dice-lang/src/bjc/dicelang/v2/Shunter.java deleted file mode 100644 index 28dafef..0000000 --- a/dice-lang/src/bjc/dicelang/v2/Shunter.java +++ /dev/null @@ -1,258 +0,0 @@ -package bjc.dicelang.v2; - -import bjc.utils.funcdata.FunctionalList; -import bjc.utils.funcdata.FunctionalMap; -import bjc.utils.funcdata.IList; -import bjc.utils.funcdata.IMap; - -import static bjc.dicelang.v2.Errors.ErrorKey.*; -import static bjc.dicelang.v2.Token.Type.*; - -import java.util.Deque; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.Set; - -public class Shunter { - // The binary operators and their - // priorities - private IMap ops; - - // Unary operators that can only be - // applied to non-operator tokens and yield operator tokens - private Set unaryAdjectives; - - // Unary operators that can only be - // applied to operator tokens and yield operator tokens - private Set unaryAdverbs; - - // Unary operators that can only be - // applied to operator tokens and yield data tokens - private Set unaryGerunds; - - private final int MATH_PREC = 20; - private final int DICE_PREC = 10; - private final int EXPR_PREC = 0; - - public Shunter() { - ops = new FunctionalMap<>(); - - unaryAdjectives = new HashSet<>(); - unaryAdverbs = new HashSet<>(); - unaryGerunds = new HashSet<>(); - - unaryAdverbs.add(COERCE); - - ops.put(ADD, 0 + MATH_PREC); - ops.put(SUBTRACT, 0 + MATH_PREC); - - ops.put(MULTIPLY, 1 + MATH_PREC); - ops.put(IDIVIDE, 1 + MATH_PREC); - ops.put(DIVIDE, 1 + MATH_PREC); - - ops.put(DICEGROUP, 0 + DICE_PREC); - - ops.put(DICECONCAT, 1 + DICE_PREC); - - ops.put(DICELIST, 2 + DICE_PREC); - - ops.put(LET, 0 + EXPR_PREC); - ops.put(BIND, 1 + EXPR_PREC); - } - - private boolean isUnary(Token tk) { - Token.Type ty = tk.type; - - if(unaryAdjectives.contains(ty)) return true; - if(unaryAdverbs.contains(ty)) return true; - if(unaryGerunds.contains(ty)) return true; - - return false; - } - - private boolean isOp(Token tk) { - Token.Type ty = tk.type; - - if(ops.containsKey(ty)) return true; - if(unaryAdjectives.contains(ty)) return true; - if(unaryAdverbs.contains(ty)) return true; - if(unaryGerunds.contains(ty)) return true; - if(ty == TAGOPR) return true; - - return false; - } - - private boolean shuntToken(Token tk, Deque opStack, - Deque unaryStack, Deque currReturned, - Deque feed) { - if(unaryStack.size() != 0) { - if(isUnary(tk)) { - unaryStack.add(tk); - return true; - } - - Token unaryOp = unaryStack.pop(); - - Token.Type unaryType = unaryOp.type; - - if(unaryAdjectives.contains(unaryType)) { - if(isOp(tk)) { - Errors.inst.printError(EK_SHUNT_NOTADV, unaryOp.toString(), tk.toString()); - return false; - } - - Token newTok = new Token(TAGOPR); - - if(tk.type == TAGOP) { - newTok.tokenValues = tk.tokenValues; - } else { - newTok.tokenValues = new FunctionalList<>(tk); - } - - newTok.tokenValues.add(unaryOp); - opStack.push(newTok); - - return true; - } else if(unaryAdverbs.contains(unaryType)) { - if(!isOp(tk)) { - Errors.inst.printError(EK_SHUNT_NOTADJ, unaryOp.toString(), tk.toString()); - return false; - } - - Token newTok = new Token(TAGOPR); - - if(tk.type == TAGOP) { - newTok.tokenValues = tk.tokenValues; - } else { - newTok.tokenValues = new FunctionalList<>(tk); - } - - newTok.tokenValues.add(unaryOp); - opStack.push(newTok); - - return true; - } - } - - if(isUnary(tk)) { - unaryStack.add(tk); - return true; - } else if(isOp(tk)) { - while(!opStack.isEmpty() && isHigherPrec(tk, opStack.peek())) { - currReturned.addLast(opStack.pop()); - } - - opStack.push(tk); - } else if(tk.type == OPAREN || tk.type == OBRACE) { - opStack.push(tk); - - if(tk.type == OBRACE) currReturned.addLast(tk); - } else if(tk.type == CPAREN || tk.type == CBRACE) { - Token matching = null; - - switch(tk.type) { - case CPAREN: - matching = new Token(OPAREN, tk.intValue); - break; - case CBRACE: - matching = new Token(OBRACE, tk.intValue); - break; - default: - break; - } - - if(!opStack.contains(matching)) { - Errors.inst.printError(EK_SHUNT_NOGROUP, tk.toString(), matching.toString()); - return false; - } - - while(!opStack.peek().equals(matching)) { - currReturned.addLast(opStack.pop()); - } - - if(tk.type == CBRACE) { - currReturned.addLast(tk); - } - - opStack.pop(); - } else if(tk.type == GROUPSEP) { - IList group = new FunctionalList<>(); - - while(currReturned.size() != 0 && !currReturned.peek().isGrouper()) { - group.add(currReturned.pop()); - } - - while(opStack.size() != 0 && !opStack.peek().isGrouper()) { - group.add(opStack.pop()); - } - - if(currReturned.size() == 0) { - Errors.inst.printError(EK_SHUNT_INVSEP); - return false; - } - - currReturned.addLast(new Token(TOKGROUP, group)); - } else { - currReturned.addLast(tk); - } - - return true; - } - - public boolean shuntTokens(IList tks, IList returned) { - Deque opStack = new LinkedList<>(); - Deque unaryOps = new LinkedList<>(); - - Deque currReturned = new LinkedList<>(); - - Deque feed = new LinkedList<>(); - - for(Token tk : tks.toIterable()) { - while(feed.size() != 0) - shuntToken(feed.poll(), opStack, unaryOps, currReturned, feed); - shuntToken(tk, opStack, unaryOps, currReturned, feed); - } - - // Flush leftover operators - while(!opStack.isEmpty()) { - currReturned.addLast(opStack.pop()); - } - - for(Token tk : currReturned) { - returned.add(tk); - } - - return true; - } - - private boolean isHigherPrec(Token lft, Token rght) { - Token.Type left = lft.type; - Token.Type right = rght.type; - - boolean exists = ops.containsKey(right); - - if(rght.type == TAGOPR) exists = true; - - // If it doesn't, the left is higher precedence. - if (!exists) { - return false; - } - - int rightPrecedence; - int leftPrecedence; - - if(rght.type == TAGOPR) { - rightPrecedence = (int)rght.intValue; - } else { - rightPrecedence = ops.get(right); - } - - if(lft.type == TAGOPR) { - leftPrecedence = (int)lft.intValue; - } else { - leftPrecedence = ops.get(left); - } - - return rightPrecedence >= leftPrecedence; - } -} diff --git a/dice-lang/src/bjc/dicelang/v2/StreamEngine.java b/dice-lang/src/bjc/dicelang/v2/StreamEngine.java deleted file mode 100644 index cd43e92..0000000 --- a/dice-lang/src/bjc/dicelang/v2/StreamEngine.java +++ /dev/null @@ -1,118 +0,0 @@ -package bjc.dicelang.v2; - -import bjc.utils.funcdata.FunctionalList; -import bjc.utils.funcdata.IList; -import bjc.utils.funcutils.ListUtils; - -import static bjc.dicelang.v2.Errors.ErrorKey.*; - -import bjc.utils.esodata.SingleTape; -import bjc.utils.esodata.Tape; - -public class StreamEngine { - private DiceLangEngine eng; - - private Tape> streams; - private IList currStream; - - public StreamEngine(DiceLangEngine engine) { - eng = engine; - } - - private void init() { - streams = new SingleTape<>(); - - currStream = new FunctionalList<>(); - streams.insertBefore(currStream); - } - - public boolean doStreams(String[] toks, IList dest) { - init(); - - boolean quoteMode = false; - - for(String tk : toks) { - if(tk.startsWith("{@S") && !quoteMode) { - if(tk.equals("{@SQ}")) { - quoteMode = true; - } else if(!processCommand(tk)) { - return false; - } - // Command ran correctly, continue - } else { - if(tk.equals("{@SU}")) { - quoteMode = false; - } else if(tk.startsWith("\\") && tk.endsWith("{@SU}")) { - currStream.add(tk.substring(1)); - } else { - currStream.add(tk); - } - } - } - - for(String tk : currStream) { - dest.add(tk); - } - - return true; - } - - private boolean processCommand(String tk) { - char[] comms = null; - - if(tk.length() > 5) { - comms = tk.substring(3, tk.length() - 1).toCharArray(); - } else { - comms = new char[1]; - comms[0] = tk.charAt(3); - } - - for(char comm : comms) { - switch(comm) { - case '+': - streams.insertAfter(new FunctionalList<>()); - break; - case '>': - if(!streams.right()) { - Errors.inst.printError(EK_STRM_NONEX); - return false; - } - - currStream = streams.item(); - break; - case '<': - if(!streams.left()) { - Errors.inst.printError(EK_STRM_NONEX); - return false; - } - - currStream = streams.item(); - break; - case '-': - if(streams.size() == 1) { - Errors.inst.printError(EK_STRM_LAST); - return false; - } else { - streams.remove(); - currStream = streams.item(); - } - break; - case 'S': - if(streams.size() == 1) { - Errors.inst.printError(EK_STRM_LAST); - return false; - } else { - IList stringLit = streams.remove(); - currStream = streams.item(); - currStream.add(ListUtils.collapseTokens(stringLit, " ")); - } - break; - default: - Errors.inst.printError(EK_STRM_INVCOM, tk); - return false; - } - } - - return true; - } -} diff --git a/dice-lang/src/bjc/dicelang/v2/Token.java b/dice-lang/src/bjc/dicelang/v2/Token.java deleted file mode 100644 index 3d8359f..0000000 --- a/dice-lang/src/bjc/dicelang/v2/Token.java +++ /dev/null @@ -1,140 +0,0 @@ -package bjc.dicelang.v2; - -import bjc.dicelang.v2.dice.DieExpression; -import bjc.utils.funcdata.IList; - -/** - * Lexer token - */ -public class Token { - public final static Token NIL_TOKEN = new Token(Type.NIL); - - /** - * Possible token types - */ - public static enum Type { - // Natural tokens - // These are produced from lexemes - ADD, SUBTRACT, - MULTIPLY, - DIVIDE, IDIVIDE, - INT_LIT, FLOAT_LIT, STRING_LIT, - VREF, - DICE_LIT, DICEGROUP, DICECONCAT, DICELIST, - LET, BIND, COERCE, - OPAREN, CPAREN, - OBRACKET, CBRACKET, - OBRACE, CBRACE, - - // Synthetic tokens - // These are produced when needed - NIL, GROUPSEP, TOKGROUP, - TAGOP, TAGOPR - } - - public final Type type; - - // This is used for the following token types - // INT_LIT (int value) - // STRING_LIT (index into string table) - // VREF (index into sym table) - // O* and C* (sym-count of current token) - public long intValue; - - // This is used for the following token types - // FLOAT_LIT (float value) - public double floatValue; - - // This is used for the following token types - // DICE_LIT (dice value) - public DieExpression diceValue; - - // This is used for the following token types - // TOKGROUP (the tokens in the group) - // TAG* (the tagged construct) - public IList tokenValues; - - public Token(Type typ) { - type = typ; - } - - public Token(Type typ, long val) { - this(typ); - - intValue = val; - } - - public Token(Type typ, double val) { - this(typ); - - floatValue = val; - } - - public Token(Type typ, DieExpression val) { - this(typ); - - diceValue = val; - } - - public Token(Type typ, IList tkVals) { - this(typ); - - tokenValues = tkVals; - } - - public String toString() { - switch(type) { - case INT_LIT: - case STRING_LIT: - case VREF: - case OPAREN: - case CPAREN: - case OBRACKET: - case CBRACKET: - case OBRACE: - case CBRACE: - return type.toString() + "(" - + intValue + ")"; - case FLOAT_LIT: - return type.toString() + "(" - + floatValue + ")"; - case DICE_LIT: - return type.toString() + "(" - + diceValue + ")"; - case TAGOP: - case TAGOPR: - case TOKGROUP: - return type.toString() + "(" - + tokenValues + ")"; - default: - return type.toString(); - } - } - - public boolean equals(Object other) { - if(!(other instanceof Token)) return false; - - Token otk = (Token)other; - - if(otk.type != type) return false; - - switch(type) { - case OBRACE: - case OBRACKET: - return intValue == otk.intValue; - default: - return true; - } - } - - public boolean isGrouper() { - switch(type) { - case OPAREN: - case OBRACE: - case OBRACKET: - return true; - default: - return false; - } - } -} diff --git a/dice-lang/src/bjc/dicelang/v2/Tokenizer.java b/dice-lang/src/bjc/dicelang/v2/Tokenizer.java deleted file mode 100644 index 40b1285..0000000 --- a/dice-lang/src/bjc/dicelang/v2/Tokenizer.java +++ /dev/null @@ -1,154 +0,0 @@ -package bjc.dicelang.v2; - -import static bjc.dicelang.v2.Errors.ErrorKey.*; -import static bjc.dicelang.v2.Token.Type.*; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import bjc.dicelang.v2.dice.DiceBox; -import bjc.utils.funcdata.FunctionalMap; -import bjc.utils.funcdata.IMap; -import bjc.utils.funcutils.StringUtils; - -public class Tokenizer { - // Literal tokens for tokenization - private IMap litTokens; - - private DiceLangEngine eng; - - private int nextSym = 0; - - public Tokenizer(DiceLangEngine engine) { - eng = engine; - - litTokens = new FunctionalMap<>(); - - litTokens.put("+", ADD); - litTokens.put("-", SUBTRACT); - litTokens.put("*", MULTIPLY); - litTokens.put("/", DIVIDE); - litTokens.put("//", IDIVIDE); - litTokens.put("dg", DICEGROUP); - litTokens.put("dc", DICECONCAT); - litTokens.put("dl", DICELIST); - litTokens.put("=>", LET); - litTokens.put(":=", BIND); - litTokens.put(",", GROUPSEP); - litTokens.put("crc", COERCE); - } - - public Token lexToken(String token, IMap stringLts) { - if(token.equals("")) return null; - - Token tk = Token.NIL_TOKEN; - - if(litTokens.containsKey(token)) { - tk = new Token(litTokens.get(token)); - } else { - switch(token.charAt(0)) { - case '(': - case ')': - case '[': - case ']': - case '{': - case '}': - tk = tokenizeGrouping(token); - break; - default: - tk = tokenizeLiteral(token, stringLts); - } - } - - return tk; - } - - private Token tokenizeGrouping(String token) { - Token tk = Token.NIL_TOKEN; - - if(StringUtils.containsOnly(token, "\\" + token.charAt(0))) { - switch(token.charAt(0)) { - case '(': - tk = new Token(OPAREN, token.length()); - break; - case ')': - tk = new Token(CPAREN, token.length()); - break; - case '[': - tk = new Token(OBRACKET, token.length()); - break; - case ']': - tk = new Token(CBRACKET, token.length()); - break; - case '{': - tk = new Token(OBRACE, token.length()); - break; - case '}': - tk = new Token(CBRACE, token.length()); - break; - default: - Errors.inst.printError(EK_TOK_UNGROUP, token); - break; - } - } - - return tk; - } - - private Pattern intMatcher = Pattern.compile("\\A[\\-\\+]?\\d+\\Z"); - private Pattern hexadecimalMatcher = Pattern.compile("\\A[\\-\\+]?0x[0-9A-Fa-f]+\\Z"); - private Pattern flexadecimalMatcher = Pattern.compile("\\A[\\-\\+]?[0-9][0-9A-Za-z]+B\\d{1,2}\\Z"); - private Pattern stringLitMatcher = Pattern.compile("\\AstringLiteral(\\d+)\\Z"); - - private Token tokenizeLiteral(String token, IMap stringLts) { - Token tk = Token.NIL_TOKEN; - - if(intMatcher.matcher(token).matches()) { - tk = new Token(INT_LIT, Long.parseLong(token)); - } else if(hexadecimalMatcher.matcher(token).matches()) { - String newToken = token.substring(0, 1) + token.substring(token.indexOf('x')); - - tk = new Token(INT_LIT, Long.parseLong(newToken.substring(2).toUpperCase(), 16)); - } else if(flexadecimalMatcher.matcher(token).matches()) { - int parseBase = Integer.parseInt(token.substring(token.lastIndexOf('B') + 1)); - - if(parseBase < Character.MIN_RADIX || parseBase > Character.MAX_RADIX) { - Errors.inst.printError(EK_TOK_INVBASE, Integer.toString(parseBase)); - return Token.NIL_TOKEN; - } - - String flexNum = token.substring(0, token.lastIndexOf('B')); - - try { - tk = new Token(INT_LIT, Long.parseLong(flexNum, parseBase)); - } catch (NumberFormatException nfex) { - Errors.inst.printError(EK_TOK_INVFLEX, flexNum, Integer.toString(parseBase)); - return Token.NIL_TOKEN; - } - } else if(DoubleMatcher.floatingLiteral.matcher(token).matches()) { - tk = new Token(FLOAT_LIT, Double.parseDouble(token)); - } else if(DiceBox.isValidExpression(token)) { - tk = new Token(DICE_LIT, DiceBox.parseExpression(token)); - } else { - Matcher stringLit = stringLitMatcher.matcher(token); - - if(stringLit.matches()) { - int litNum = Integer.parseInt(stringLit.group(1)); - - eng.stringLits.put(litNum, stringLts.get(token)); - tk = new Token(STRING_LIT, litNum); - } else { - // @TODO define what a valid identifier is - eng.symTable.put(nextSym++, token); - - tk = new Token(VREF, nextSym - 1); - } - - // @TODO uncomment when we have a defn. for var names - // System.out.printf("\tERROR: Unrecognized token:" - // + "%s\n", token); - } - - return tk; - } -} diff --git a/dice-lang/src/bjc/dicelang/v2/dice/CompoundDie.java b/dice-lang/src/bjc/dicelang/v2/dice/CompoundDie.java deleted file mode 100644 index a8186eb..0000000 --- a/dice-lang/src/bjc/dicelang/v2/dice/CompoundDie.java +++ /dev/null @@ -1,31 +0,0 @@ -package bjc.dicelang.v2.dice; - -public class CompoundDie implements Die { - private Die left; - private Die right; - - public CompoundDie(Die lft, Die rght) { - left = lft; - right = rght; - } - - public boolean canOptimize() { - return left.canOptimize() && right.canOptimize(); - } - - public long optimize() { - return Long.parseLong(left.optimize() + "" + right.optimize()); - } - - public long roll() { - return Long.parseLong(left.roll() + "" + right.roll()); - } - - public long rollSingle() { - return roll(); - } - - public String toString() { - return left.toString() + "c" + right.toString(); - } -} \ No newline at end of file diff --git a/dice-lang/src/bjc/dicelang/v2/dice/CompoundingDie.java b/dice-lang/src/bjc/dicelang/v2/dice/CompoundingDie.java deleted file mode 100644 index d5991ae..0000000 --- a/dice-lang/src/bjc/dicelang/v2/dice/CompoundingDie.java +++ /dev/null @@ -1,63 +0,0 @@ -package bjc.dicelang.v2.dice; - -import java.util.function.Predicate; - -public class CompoundingDie implements Die { - private Die source; - - private Predicate compoundOn; - private String compoundPattern; - - public CompoundingDie(Die src, Predicate compound) { - this(src, compound, null); - } - - public CompoundingDie(Die src, Predicate compound, String patt) { - source = src; - - compoundOn = compound; - compoundPattern = patt; - } - - public boolean canOptimize() { - return source.canOptimize() && source.optimize() == 0; - } - - public long optimize() { - return 0; - } - - public long roll() { - long res = source.roll(); - long oldRes = res; - - while(compoundOn.test(oldRes)) { - oldRes = source.rollSingle(); - - res += oldRes; - } - - return res; - } - - public long rollSingle() { - long res = source.rollSingle(); - long oldRes = res; - - while(compoundOn.test(oldRes)) { - oldRes = source.rollSingle(); - - res += oldRes; - } - - return res; - } - - public String toString() { - if(compoundPattern == null) { - return source + "!!"; - } else { - return source + "!!" + compoundPattern; - } - } -} \ No newline at end of file diff --git a/dice-lang/src/bjc/dicelang/v2/dice/DiceBox.java b/dice-lang/src/bjc/dicelang/v2/dice/DiceBox.java deleted file mode 100644 index 995c3bf..0000000 --- a/dice-lang/src/bjc/dicelang/v2/dice/DiceBox.java +++ /dev/null @@ -1,142 +0,0 @@ -package bjc.dicelang.v2.dice; - -import java.util.Random; -import java.util.function.Predicate; -import java.util.regex.Pattern; - -public class DiceBox { - static final Random rng = new Random(); - - public static DieExpression parseExpression(String exp) { - if(!isValidExpression(exp)) return null; - - if(scalarDiePattern.matcher(exp).matches()) { - Die scal = new ScalarDie(Long.parseLong(exp.substring(0, exp.indexOf('s')))); - - return new DieExpression(scal); - } else if(simpleDiePattern.matcher(exp).matches()) { - String[] dieParts = exp.split("d"); - - long right = Long.parseLong(dieParts[1]); - if(dieParts[0].equals("")) { - Die scal = new SimpleDie(1, right); - return new DieExpression(scal); - } else { - Die scal = new SimpleDie(Long.parseLong(dieParts[0]), right); - return new DieExpression(scal); - } - } else if(fudgeDiePattern.matcher(exp).matches()) { - String nDice = exp.substring(0, exp.indexOf('d')); - - return new DieExpression(new FudgeDie(Long.parseLong(nDice))); - } else if(compoundDiePattern.matcher(exp).matches()) { - String[] dieParts = exp.split("c"); - - DieExpression left = parseExpression(dieParts[0]); - DieExpression right = parseExpression(dieParts[1]); - - return new DieExpression(new CompoundDie(left.scalar, right.scalar)); - } else if(compoundingDiePattern.matcher(exp).matches()) { - String[] dieParts = exp.split("!!"); - - DieExpression left = parseExpression(dieParts[0]); - Predicate right = deriveCond(dieParts[1]); - - Die scal = new CompoundingDie(left.scalar, right, dieParts[1]); - return new DieExpression(scal); - } else if(explodingDiePattern.matcher(exp).matches()) { - String[] dieParts = exp.split("!"); - - DieExpression left = parseExpression(dieParts[0]); - Predicate right = deriveCond(dieParts[1]); - - DieList lst = new ExplodingDice(left.scalar, right, dieParts[1], false); - return new DieExpression(lst); - } else if(penetratingDiePattern.matcher(exp).matches()) { - String[] dieParts = exp.split("p!"); - - DieExpression left = parseExpression(dieParts[0]); - Predicate right = deriveCond(dieParts[1]); - - DieList lst = new ExplodingDice(left.scalar, right, dieParts[1], true); - return new DieExpression(lst); - } else if(diceListPattern.matcher(exp).matches()) { - String[] dieParts = exp.split("dl"); - - DieExpression left = parseExpression(dieParts[0]); - DieExpression right = parseExpression(dieParts[1]); - - DieList lst = new SimpleDieList(left.scalar, right.scalar); - return new DieExpression(lst); - } - - // @TODO give a specific error message - return null; - } - - private static final String comparePoint = "[<>=]\\d+"; - - private static final String scalarDie = "[\\+\\-]?\\d+sd"; - private static final Pattern scalarDiePattern = Pattern.compile("\\A" + scalarDie + "\\Z"); - - private static final String simpleDie = "(?:\\d+)?d\\d+"; - private static final Pattern simpleDiePattern = Pattern.compile("\\A" + simpleDie + "\\Z"); - - private static final String fudgeDie = "(?:\\d+)?dF"; - private static final Pattern fudgeDiePattern = Pattern.compile("\\A" + fudgeDie + "\\Z"); - - private static final String compoundDie = simpleDie + "c(?:(?:" + simpleDie + ")|(?:\\d+))"; - private static final Pattern compoundDiePattern = Pattern.compile("\\A" + compoundDie + "\\Z"); - - private static final String compoundGroup = "(?:(?:" + scalarDie + ")|(?:" + simpleDie + ")|(?:" - + compoundDie + ")|(?:" + fudgeDie +"))"; - - private static final String compoundingDie = compoundGroup + "!!" + comparePoint; - private static final Pattern compoundingDiePattern = Pattern.compile("\\A" + compoundingDie + "\\Z"); - - private static final String explodingDie = compoundGroup + "!" + comparePoint; - private static final Pattern explodingDiePattern = Pattern.compile("\\A" + explodingDie + "\\Z"); - - private static final String penetratingDie = compoundGroup + "!" + comparePoint; - private static final Pattern penetratingDiePattern = Pattern.compile("\\A" + penetratingDie + "\\Z"); - - private static final String diceList = compoundGroup + "dl" + compoundGroup; - private static final Pattern diceListPattern = Pattern.compile("\\A" + diceList + "\\Z"); - - public static boolean isValidExpression(String exp) { - if(scalarDiePattern.matcher(exp).matches()) { - return true; - } else if(simpleDiePattern.matcher(exp).matches()) { - return true; - } else if(fudgeDiePattern.matcher(exp).matches()) { - return true; - } else if(compoundDiePattern.matcher(exp).matches()) { - return true; - } else if(compoundingDiePattern.matcher(exp).matches()) { - return true; - } else if(explodingDiePattern.matcher(exp).matches()) { - return true; - } else if(penetratingDiePattern.matcher(exp).matches()) { - return true; - } else if (diceListPattern.matcher(exp).matches()) { - return true; - } else { - return false; - } - } - - private static Predicate deriveCond(String patt) { - long num = Long.parseLong(patt.substring(1)); - - switch(patt.charAt(0)) { - case '<': - return (roll) -> roll < num; - case '=': - return (roll) -> roll == num; - case '>': - return (roll) -> roll > num; - default: - return (roll) -> false; - } - } -} diff --git a/dice-lang/src/bjc/dicelang/v2/dice/Die.java b/dice-lang/src/bjc/dicelang/v2/dice/Die.java deleted file mode 100644 index 808d7fd..0000000 --- a/dice-lang/src/bjc/dicelang/v2/dice/Die.java +++ /dev/null @@ -1,9 +0,0 @@ -package bjc.dicelang.v2.dice; - -public interface Die { - boolean canOptimize(); - long optimize(); - - long roll(); - long rollSingle(); -} \ No newline at end of file diff --git a/dice-lang/src/bjc/dicelang/v2/dice/DieExpression.java b/dice-lang/src/bjc/dicelang/v2/dice/DieExpression.java deleted file mode 100644 index 93fcbb9..0000000 --- a/dice-lang/src/bjc/dicelang/v2/dice/DieExpression.java +++ /dev/null @@ -1,30 +0,0 @@ -package bjc.dicelang.v2.dice; - -import java.util.Arrays; - -public class DieExpression { - public final boolean isList; - - public Die scalar; - public DieList list; - - public DieExpression(Die scal) { - isList = false; - scalar = scal; - } - - public DieExpression(DieList lst) { - isList = true; - list = lst; - } - - public String toString() { - if(isList) return list.toString(); - else return scalar.toString(); - } - - public String value() { - if(isList) return Arrays.toString(list.roll()); - else return Long.toString(scalar.roll()); - } -} \ No newline at end of file diff --git a/dice-lang/src/bjc/dicelang/v2/dice/DieList.java b/dice-lang/src/bjc/dicelang/v2/dice/DieList.java deleted file mode 100644 index ab3c7b7..0000000 --- a/dice-lang/src/bjc/dicelang/v2/dice/DieList.java +++ /dev/null @@ -1,8 +0,0 @@ -package bjc.dicelang.v2.dice; - -public interface DieList { - boolean canOptimize(); - long[] optimize(); - - long[] roll(); -} \ No newline at end of file diff --git a/dice-lang/src/bjc/dicelang/v2/dice/ExplodingDice.java b/dice-lang/src/bjc/dicelang/v2/dice/ExplodingDice.java deleted file mode 100644 index 40ff1e0..0000000 --- a/dice-lang/src/bjc/dicelang/v2/dice/ExplodingDice.java +++ /dev/null @@ -1,70 +0,0 @@ -package bjc.dicelang.v2.dice; - -import java.util.LinkedList; -import java.util.List; -import java.util.function.Predicate; - -public class ExplodingDice implements DieList { - private Die source; - - private Predicate explodeOn; - private String explodePattern; - private boolean explodePenetrates; - - public ExplodingDice(Die src, Predicate explode) { - this(src, explode, null, false); - } - - public ExplodingDice(Die src, Predicate explode, boolean penetrate) { - this(src, explode, null, penetrate); - } - - public ExplodingDice(Die src, Predicate explode, String patt, - boolean penetrate) { - source = src; - explodeOn = explode; - explodePattern = patt; - explodePenetrates = penetrate; - } - - public boolean canOptimize() { - return false; - } - - public long[] optimize() { - return new long[0]; - } - - public long[] roll() { - long res = source.roll(); - long oldRes = res; - - List resList = new LinkedList<>(); - - while(explodeOn.test(oldRes)) { - oldRes = source.rollSingle(); - - if(explodePenetrates) oldRes -= 1; - resList.add(oldRes); - } - - long[] newRes = new long[resList.size() + 1]; - newRes[0] = res; - - int i = 1; - for(long rll : resList) { - newRes[i] = rll; - i += 1; - } - - return newRes; - } - - public String toString() { - if(explodePattern == null) { - return source + (explodePenetrates ? "p" : "") + "!"; - } else { - return source + (explodePenetrates ? "p" : "") + "!" + explodePattern; - } - } -} \ No newline at end of file diff --git a/dice-lang/src/bjc/dicelang/v2/dice/FudgeDie.java b/dice-lang/src/bjc/dicelang/v2/dice/FudgeDie.java deleted file mode 100644 index 4c8c52a..0000000 --- a/dice-lang/src/bjc/dicelang/v2/dice/FudgeDie.java +++ /dev/null @@ -1,37 +0,0 @@ -package bjc.dicelang.v2.dice; - -public class FudgeDie implements Die { - private Die numDice; - - public FudgeDie(long nDice) { - numDice = new ScalarDie(nDice); - } - - public boolean canOptimize() { - return numDice.canOptimize() && numDice.optimize() == 0; - } - - public long optimize() { - return 0; - } - - public long roll() { - long res = 0; - - long nDice = numDice.roll(); - - for(int i = 0; i < nDice; i++) { - res += rollSingle(); - } - - return res; - } - - public long rollSingle() { - return DiceBox.rng.nextInt(3) - 1; - } - - public String toString() { - return numDice + "dF"; - } -} \ No newline at end of file diff --git a/dice-lang/src/bjc/dicelang/v2/dice/MathDie.java b/dice-lang/src/bjc/dicelang/v2/dice/MathDie.java deleted file mode 100644 index 55e01f8..0000000 --- a/dice-lang/src/bjc/dicelang/v2/dice/MathDie.java +++ /dev/null @@ -1,74 +0,0 @@ -package bjc.dicelang.v2.dice; - -public class MathDie implements Die { - public static enum MathOp { - ADD, SUBTRACT, MULTIPLY; - - public String toString() { - switch(this) { - case ADD: - return "+"; - case SUBTRACT: - return "-"; - case MULTIPLY: - return "*"; - default: - return this.name(); - } - } - } - - private MathDie.MathOp type; - - private Die left; - private Die right; - - public MathDie(MathDie.MathOp op, Die lft, Die rght) { - type = op; - - left = lft; - right = rght; - } - - public boolean canOptimize() { - return left.canOptimize() && right.canOptimize(); - } - - private long performOp(long lft, long rght) { - switch(type) { - case ADD: - return lft + rght; - case SUBTRACT: - return lft - rght; - case MULTIPLY: - return lft * rght; - default: - return 0; - } - } - - public long optimize() { - long lft = left.optimize(); - long rght = right.optimize(); - - return performOp(lft, rght); - } - - public long roll() { - long lft = left.roll(); - long rght = right.roll(); - - return performOp(lft, rght); - } - - public long rollSingle() { - long lft = left.rollSingle(); - long rght = right.rollSingle(); - - return performOp(lft, rght); - } - - public String toString() { - return left.toString() + " " + type.toString() + " " + right.toString(); - } -} \ No newline at end of file diff --git a/dice-lang/src/bjc/dicelang/v2/dice/ScalarDie.java b/dice-lang/src/bjc/dicelang/v2/dice/ScalarDie.java deleted file mode 100644 index 17714ee..0000000 --- a/dice-lang/src/bjc/dicelang/v2/dice/ScalarDie.java +++ /dev/null @@ -1,29 +0,0 @@ -package bjc.dicelang.v2.dice; - -public class ScalarDie implements Die { - private long val; - - public ScalarDie(long vl) { - val = vl; - } - - public boolean canOptimize() { - return true; - } - - public long optimize() { - return val; - } - - public long roll() { - return val; - } - - public long rollSingle() { - return val; - } - - public String toString() { - return Long.toString(val); - } -} \ No newline at end of file diff --git a/dice-lang/src/bjc/dicelang/v2/dice/SimpleDie.java b/dice-lang/src/bjc/dicelang/v2/dice/SimpleDie.java deleted file mode 100644 index f084822..0000000 --- a/dice-lang/src/bjc/dicelang/v2/dice/SimpleDie.java +++ /dev/null @@ -1,60 +0,0 @@ -package bjc.dicelang.v2.dice; - -public class SimpleDie implements Die { - private Die numDice; - private Die diceSize; - - public SimpleDie(long nDice, long size) { - numDice = new ScalarDie(nDice); - diceSize = new ScalarDie(size); - } - - public SimpleDie(Die nDice, long size) { - numDice = nDice; - diceSize = new ScalarDie(size); - } - - public SimpleDie(long nDice, Die size) { - numDice = new ScalarDie(nDice); - diceSize = size; - } - - public SimpleDie(Die nDice, Die size) { - numDice = nDice; - diceSize = size; - } - - public boolean canOptimize() { - if(diceSize.canOptimize() && (diceSize.optimize() <= 1)) { - return numDice.canOptimize(); - } else return false; - } - - public long optimize() { - long optSize = diceSize.optimize(); - - if(optSize == 0) return 0; - else return numDice.optimize(); - } - - public long roll() { - long total = 0; - - long nDice = numDice.roll(); - long dSize = diceSize.roll(); - - for(int i = 0; i < nDice; i++) { - total += (Math.abs(DiceBox.rng.nextLong()) % dSize) + 1; - } - - return total; - } - - public long rollSingle() { - return (Math.abs(DiceBox.rng.nextLong()) % diceSize.roll()) + 1; - } - - public String toString() { - return numDice + "d" + diceSize; - } -} \ No newline at end of file diff --git a/dice-lang/src/bjc/dicelang/v2/dice/SimpleDieList.java b/dice-lang/src/bjc/dicelang/v2/dice/SimpleDieList.java deleted file mode 100644 index e5aef18..0000000 --- a/dice-lang/src/bjc/dicelang/v2/dice/SimpleDieList.java +++ /dev/null @@ -1,48 +0,0 @@ -package bjc.dicelang.v2.dice; - -public class SimpleDieList implements DieList { - private Die numDice; - private Die size; - - public SimpleDieList(Die nDice, Die sze) { - numDice = nDice; - size = sze; - } - - public boolean canOptimize() { - if(size.canOptimize() && size.optimize() <= 1) { - return numDice.canOptimize(); - } else { - return false; - } - } - - public long[] optimize() { - int sze = (int)numDice.optimize(); - long res = size.optimize(); - - long[] ret = new long[sze]; - - for(int i = 0; i < sze; i++) { - ret[i] = res; - } - - return ret; - } - - public long[] roll() { - int num = (int)numDice.roll(); - - long[] ret = new long[num]; - - for(int i = 0; i < num; i++) { - ret[i] = size.roll(); - } - - return ret; - } - - public String toString() { - return numDice.toString() + "dl" + size.toString(); - } -} \ No newline at end of file -- cgit v1.2.3