diff options
Diffstat (limited to 'dice-lang')
27 files changed, 503 insertions, 135 deletions
diff --git a/dice-lang/src/bjc/dicelang/CLIArgsParser.java b/dice-lang/src/bjc/dicelang/CLIArgsParser.java index e324e67..7f21b63 100644 --- a/dice-lang/src/bjc/dicelang/CLIArgsParser.java +++ b/dice-lang/src/bjc/dicelang/CLIArgsParser.java @@ -51,64 +51,87 @@ public class CLIArgsParser { if (!eng.toggleDebug()) { eng.toggleDebug(); } + break; + case "-nd": case "--no-debug": if (eng.toggleDebug()) { eng.toggleDebug(); } + break; + case "-po": case "--postfix": if (!eng.togglePostfix()) { eng.togglePostfix(); } + break; + case "-npo": case "--no-postfix": if (eng.togglePostfix()) { eng.togglePostfix(); } + break; + case "-pr": case "--prefix": if (!eng.togglePrefix()) { eng.togglePrefix(); } + break; + case "-npr": case "--no-prefix": if (eng.togglePrefix()) { eng.togglePrefix(); } + break; + case "-se": case "--stepeval": if (!eng.toggleStepEval()) { eng.toggleStepEval(); } + break; + case "-nse": case "--no-stepeval": if (eng.toggleStepEval()) { eng.toggleStepEval(); } + break; + case "-D": case "--define": i = simpleDefine(i, args, eng); + if (i == -1) return false; + break; + case "-df": case "--define-file": i = defineFile(i, args, eng); + if (i == -1) return false; + break; + case "-ctf": case "--compiler-tweak-file": - /* - * @TODO not yet implemented - */ + + /* + * @TODO not yet implemented + */ default: Errors.inst.printError(EK_CLI_UNARG, arg); return false; @@ -118,14 +141,16 @@ public class CLIArgsParser { return true; } - private static int simpleDefine(final int i, final String[] args, final DiceLangEngine eng) { + private static int simpleDefine(final int i, final String[] args, + final DiceLangEngine eng) { if (i >= args.length - 1) { Errors.inst.printError(EK_CLI_MISARG, "define"); return -1; } if (i >= args.length - 2) { - final Define dfn = new Define(5, false, false, false, null, args[i + 1], Arrays.asList("")); + final Define dfn = new Define(5, false, false, false, null, args[i + 1], + Arrays.asList("")); if (dfn.inError) return -1; @@ -133,7 +158,8 @@ public class CLIArgsParser { return i + 1; } - final Define dfn = new Define(5, false, false, false, null, args[i + 1], Arrays.asList(args[i + 2])); + final Define dfn = new Define(5, false, false, false, null, args[i + 1], + Arrays.asList(args[i + 2])); if (dfn.inError) return -1; @@ -141,7 +167,8 @@ public class CLIArgsParser { return i + 2; } - private static int defineFile(final int i, final String[] args, final DiceLangEngine eng) { + private static int defineFile(final int i, final String[] args, + final DiceLangEngine eng) { if (i >= args.length - 1) { Errors.inst.printError(EK_CLI_MISARG, "define-file"); return -1; @@ -155,6 +182,7 @@ public class CLIArgsParser { final String ln = scan.nextLine(); final Define dfn = parseDefine(ln.substring(ln.indexOf(' '))); + if (dfn == null || dfn.inError) return -1; if (ln.startsWith("line")) { diff --git a/dice-lang/src/bjc/dicelang/CompilerTweaker.java b/dice-lang/src/bjc/dicelang/CompilerTweaker.java index 68c50dd..bb5cbde 100644 --- a/dice-lang/src/bjc/dicelang/CompilerTweaker.java +++ b/dice-lang/src/bjc/dicelang/CompilerTweaker.java @@ -11,8 +11,8 @@ public class CompilerTweaker { /* * Bits of the compiler necessary */ - private final DiceLangEngine eng; - private final ConfigurableTokenSplitter opExpander; + private final DiceLangEngine eng; + private final ConfigurableTokenSplitter opExpander; /** * Create a new compiler tweaker. diff --git a/dice-lang/src/bjc/dicelang/Define.java b/dice-lang/src/bjc/dicelang/Define.java index 94708fd..a008e0c 100644 --- a/dice-lang/src/bjc/dicelang/Define.java +++ b/dice-lang/src/bjc/dicelang/Define.java @@ -44,20 +44,20 @@ public class Define implements UnaryOperator<String>, Comparable<Define> { /** * The priority of this definition. */ - public final int priority; + public final int priority; /** * Whether or not this definition is in error. */ - public final boolean inError; + public final boolean inError; - private boolean doRecur; - private boolean subType; + private boolean doRecur; + private boolean subType; - private Pattern predicate; - private Pattern searcher; + private Pattern predicate; + private Pattern searcher; - private Iterator<String> replacers; - private String replacer; + private Iterator<String> replacers; + private String replacer; /** * Create a new define. @@ -83,8 +83,9 @@ public class Define implements UnaryOperator<String>, Comparable<Define> { * @param replacrs * The source for replacement strings. */ - public Define(final int priorty, final boolean isSub, final boolean recur, final boolean isCircular, - final String predicte, final String searchr, final Iterable<String> replacrs) { + public Define(final int priorty, final boolean isSub, final boolean recur, + final boolean isCircular, + final String predicte, final String searchr, final Iterable<String> replacrs) { priority = priorty; doRecur = recur; subType = isSub; @@ -114,6 +115,7 @@ public class Define implements UnaryOperator<String>, Comparable<Define> { } inError = false; + /* * Check whether or not we do sub-replacements */ @@ -170,6 +172,7 @@ public class Define implements UnaryOperator<String>, Comparable<Define> { if (subType) { final StringBuffer sb = new StringBuffer(); + while (searcherMatcher.find()) { if (replacers == null) { searcherMatcher.appendReplacement(sb, ""); diff --git a/dice-lang/src/bjc/dicelang/DiceLangConsole.java b/dice-lang/src/bjc/dicelang/DiceLangConsole.java index e06cccb..bbf3db8 100644 --- a/dice-lang/src/bjc/dicelang/DiceLangConsole.java +++ b/dice-lang/src/bjc/dicelang/DiceLangConsole.java @@ -47,6 +47,9 @@ public class DiceLangConsole { * Run the console. */ public void run() { + /* + * Set up console. + */ try { read = new ConsoleReader(); } catch (final IOException ioex) { @@ -58,6 +61,9 @@ public class DiceLangConsole { String comm = null; + /* + * Read initial command. + */ try { comm = read.readLine(String.format("(%d) dice-lang> ", commandNumber)); } catch (final IOException ioex) { @@ -65,9 +71,15 @@ public class DiceLangConsole { return; } + /* + * Run commands. + */ while (!comm.equals("quit") && !comm.equals("exit")) { if (comm.startsWith("pragma")) { - final boolean success = handlePragma(comm.substring(7)); + /* + * Run pragmas. + */ + final boolean success = handlePragma(comm.substring(7)); if (success) { System.out.println("Pragma completed succesfully"); @@ -75,7 +87,11 @@ public class DiceLangConsole { System.out.println("Pragma execution failed"); } } else { - System.out.printf("\tRaw command: %s\n", comm); + /* + * Run commands. + */ + if(eng.debugMode) + System.out.printf("\tRaw command: %s\n", comm); final boolean success = eng.runCommand(comm); @@ -98,33 +114,50 @@ public class DiceLangConsole { } private boolean handlePragma(final String pragma) { - System.out.println("\tRaw pragma: " + pragma); + if(eng.debugMode) + System.out.println("\tRaw pragma: " + pragma); + /* + * Grab the name from the arguments. + */ String pragmaName = null; final int firstIndex = pragma.indexOf(' '); + + /* + * Handle argless pragmas. + */ if (firstIndex == -1) { pragmaName = pragma; } else { pragmaName = pragma.substring(0, firstIndex); } + /* + * Run pragmas. + */ 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; @@ -133,27 +166,36 @@ public class DiceLangConsole { return true; } + /* + * Run a help mode. + */ private static boolean helpMode(final 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 <priority> <type> <recursion> <guard> <circular> <patterns>..."); break; + default: System.out.println("\tNo help available for pragma " + pragma); } @@ -175,6 +217,9 @@ public class DiceLangConsole { private final Pattern slashPattern = Pattern.compile("/((?:\\\\.|[^/\\\\])*)/"); private boolean defineMode(final String defineText) { + /* + * Grab all of the separator spaces. + */ final int firstIndex = defineText.indexOf(' '); final int secondIndex = defineText.indexOf(' ', firstIndex + 1); final int thirdIndex = defineText.indexOf(' ', secondIndex + 1); @@ -182,6 +227,9 @@ public class DiceLangConsole { final int fifthIndex = defineText.indexOf(' ', fourthIndex + 1); final int sixthIndex = defineText.indexOf(' ', fifthIndex + 1); + /* + * Error if we got something we didn't need. + */ if (firstIndex == -1) { Errors.inst.printError(EK_CONS_INVDEFINE, "(no priority)"); return false; @@ -213,25 +261,32 @@ public class DiceLangConsole { 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; } - final boolean doRecur = defineText.substring(secondIndex + 1, thirdIndex).equalsIgnoreCase("true"); - final boolean hasGuard = defineText.substring(thirdIndex + 1, fourthIndex).equalsIgnoreCase("true"); - final boolean isCircular = defineText.substring(thirdIndex + 1, fourthIndex).equalsIgnoreCase("true"); + final boolean doRecur = defineText.substring(secondIndex + 1, + thirdIndex).equalsIgnoreCase("true"); + final boolean hasGuard = defineText.substring(thirdIndex + 1, + fourthIndex).equalsIgnoreCase("true"); + final boolean isCircular = defineText.substring(thirdIndex + 1, + fourthIndex).equalsIgnoreCase("true"); final String pats = defineText.substring(fifthIndex + 1).trim(); final Matcher patMatcher = slashPattern.matcher(pats); @@ -259,8 +314,9 @@ public class DiceLangConsole { replacePatterns.add(patMatcher.group(1)); } - final Define dfn = new Define(priority, subMode, doRecur, isCircular, guardPattern, searchPattern, - replacePatterns); + final Define dfn = new Define(priority, subMode, doRecur, isCircular, guardPattern, + searchPattern, + replacePatterns); if (dfn.inError) return false; diff --git a/dice-lang/src/bjc/dicelang/DiceLangEngine.java b/dice-lang/src/bjc/dicelang/DiceLangEngine.java index 7736db4..0ac088e 100644 --- a/dice-lang/src/bjc/dicelang/DiceLangEngine.java +++ b/dice-lang/src/bjc/dicelang/DiceLangEngine.java @@ -33,6 +33,8 @@ import bjc.utils.parserutils.splitter.ConfigurableTokenSplitter; * @author Ben Culkin */ public class DiceLangEngine { + public boolean debug = true; + /* * The random fields that are package private instead of private-private * are for the benefit of the tweaker, so that it can mess around with @@ -52,7 +54,7 @@ public class DiceLangEngine { /* * Debug indicator. */ - private boolean debugMode; + public boolean debugMode; /* * Should we do shunting? */ @@ -91,14 +93,14 @@ public class DiceLangEngine { */ public final IMap<Integer, String> symTable; - private final IMap<Integer, String> stringLits; - private final IMap<String, String> stringLiterals; + private final IMap<Integer, String> stringLits; + private final IMap<String, String> stringLiterals; /* * Lists of defns. */ - private final IList<Define> lineDefns; - private final IList<Define> tokenDefns; + private final IList<Define> lineDefns; + private final IList<Define> tokenDefns; /* * Are defns sorted by priority? @@ -252,7 +254,8 @@ public class DiceLangEngine { /* * Matches double-angle bracketed strings. */ - private final Pattern nonExpandPattern = Pattern.compile("<<([^\\>]*(?:\\>(?:[^\\>])*)*)>>"); + private final Pattern nonExpandPattern = + Pattern.compile("<<([^\\>]*(?:\\>(?:[^\\>])*)*)>>"); /** * Run a command to completion. @@ -394,16 +397,22 @@ public class DiceLangEngine { 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; } @@ -537,7 +546,7 @@ public class DiceLangEngine { if (debugMode) { System.out.printf("\tCommand after non-expander reinsertion: %s\n", - fullyExpandedTokens.toString()); + fullyExpandedTokens.toString()); } return fullyExpandedTokens; @@ -625,7 +634,8 @@ public class DiceLangEngine { /* * Preshunt preshunt-marked groups of tokens. */ - private boolean removePreshuntTokens(final IList<Token> lexedTokens, final IList<Token> preparedTokens) { + private boolean removePreshuntTokens(final IList<Token> lexedTokens, + final IList<Token> preparedTokens) { /* * Current nesting level of tokens. */ @@ -677,7 +687,7 @@ public class DiceLangEngine { if (debugMode) { System.out.println("\t\tPreshunted " + curBracedTokens + " into " - + preshuntTokens); + + preshuntTokens); } if (!success) return false; @@ -728,4 +738,4 @@ public class DiceLangEngine { void addStringLiteral(final int key, final String val) { stringLits.put(key, val); } -}
\ No newline at end of file +} diff --git a/dice-lang/src/bjc/dicelang/Errors.java b/dice-lang/src/bjc/dicelang/Errors.java index f5ced44..31d57b5 100644 --- a/dice-lang/src/bjc/dicelang/Errors.java +++ b/dice-lang/src/bjc/dicelang/Errors.java @@ -277,10 +277,13 @@ public class Errors { } else { System.out.println("\t? " + key.ordinal()); } + break; + case DEV: devError(key, args); break; + default: System.out.println("\tERROR ERROR: Unknown error mode " + mode); } @@ -291,158 +294,209 @@ public class Errors { 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]); + "\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"); + + " 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]); + 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 operands, not %s\n" - + "\tProblem node is %s\n", args[0], args[1]); + + "\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_INVDCREATE: - System.out.printf("\tERROR: Dice creation operator expects integers," + " not %s\n", args[0]); + System.out.printf("\tERROR: Dice creation operator expects integers," + " not %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]); + 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_EVAL_INVSTRING: System.out.printf("\tERROR: Incorrect type %s to string operator\n", args[0]); break; + case EK_EVAL_UNSTRING: System.out.printf("\tERROR: Unknown string operator %s\n", args[0]); 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]); + + ", 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]); + + " 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]); + + " 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]); + + " 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]); + args[1]); break; + case EK_SHUNT_NOTASSOC: System.out.printf("\tERROR: Attempted to chain non-associative operator %s\n", args[0]); 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; + case EK_SCL_INVTOKEN: System.out.printf("\tERROR: Unknown SCL token %s\n", args[0]); break; + case EK_SCL_MMQUOTE: System.out.printf("\tERROR: Mismatched delimiter in SCL command\n"); break; + case EK_SCL_SUNDERFLOW: System.out.printf("\tERROR: Not enough items in stack for word %s\n", args[0]); break; + case EK_SCL_UNWORD: System.out.printf("\tERROR: Unknown word %s\n", args[0]); break; + case EK_CLI_UNARG: System.out.printf("\tERROR: Unknown argument %s\n", args[0]); break; + case EK_CLI_MISARG: System.out.printf("\tERROR: Missing subargument to command %s", args[0]); break; + case EK_CLI_INVDFNTYPE: System.out.printf("\tERROR: Invalid define type %s\n", args[0]); break; + case EK_MISC_IOEX: System.out.printf("\tERROR: I/O problem with file\n"); break; + case EK_MISC_NOFILE: System.out.printf("\tERROR: No such file %s\n", args[0]); break; + default: System.out.printf("\tERROR ERROR: Unknown error key %s\n", key); } diff --git a/dice-lang/src/bjc/dicelang/Evaluator.java b/dice-lang/src/bjc/dicelang/Evaluator.java index 5260bab..b1a1ebd 100644 --- a/dice-lang/src/bjc/dicelang/Evaluator.java +++ b/dice-lang/src/bjc/dicelang/Evaluator.java @@ -74,7 +74,8 @@ public class Evaluator { } private static Node FAIL(final EvaluatorResult res) { - return new Node(Node.Type.RESULT, new EvaluatorResult(FAILURE, new Node(Node.Type.RESULT, res))); + return new Node(Node.Type.RESULT, new EvaluatorResult(FAILURE, new Node(Node.Type.RESULT, + res))); } private final DiceLangEngine eng; @@ -114,7 +115,7 @@ public class Evaluator { }; final ITree<Node> res = comm.topDownTransform(this::pickEvaluationType, - node -> this.evaluateNode(node, ctx)); + node -> this.evaluateNode(node, ctx)); return res.getHead().resultVal; } @@ -139,9 +140,11 @@ public class Evaluator { switch (nd.operatorType) { case COERCE: return TopDownTransformResult.RTRANSFORM; + default: return TopDownTransformResult.PUSHDOWN; } + default: return TopDownTransformResult.PUSHDOWN; } @@ -151,14 +154,19 @@ public class Evaluator { 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)); @@ -222,6 +230,7 @@ public class Evaluator { if (curLevel == CoerceSteps.DOUBLE) { nd.resultVal = new EvaluatorResult(FLOAT, (double) res.intVal); } + default: /* * Do nothing @@ -233,6 +242,7 @@ public class Evaluator { } return retVal; + case DICESCALAR: final EvaluatorResult opr = ast.getChild(0).getHead().resultVal; @@ -241,7 +251,8 @@ public class Evaluator { } return new Tree<>(new Node(Node.Type.RESULT, - new EvaluatorResult(DICE, new ScalarDie(opr.intVal)))); + new EvaluatorResult(DICE, new ScalarDie(opr.intVal)))); + case DICEFUDGE: final EvaluatorResult oprn = ast.getChild(0).getHead().resultVal; @@ -250,7 +261,8 @@ public class Evaluator { } return new Tree<>(new Node(Node.Type.RESULT, - new EvaluatorResult(DICE, new FudgeDie(oprn.intVal)))); + new EvaluatorResult(DICE, new FudgeDie(oprn.intVal)))); + default: Errors.inst.printError(EK_EVAL_INVUNARY, ast.getHead().operatorType.toString()); return new Tree<>(FAIL(ast)); @@ -262,7 +274,7 @@ public class Evaluator { if (ast.getChildrenCount() != 2) { Errors.inst.printError(EK_EVAL_INVBIN, Integer.toString(ast.getChildrenCount()), - ast.toString()); + ast.toString()); return new Tree<>(FAIL(ast)); } @@ -276,22 +288,29 @@ public class Evaluator { case MULTIPLY: case DIVIDE: case IDIVIDE: - return evaluateMathBinary(binOp, left.getHead().resultVal, right.getHead().resultVal, ctx); + 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); + return evaluateDiceBinary(binOp, left.getHead().resultVal, right.getHead().resultVal, + ctx); + case STRCAT: case STRREP: - return evaluateStringBinary(binOp, left.getHead().resultVal, right.getHead().resultVal, ctx); + return evaluateStringBinary(binOp, left.getHead().resultVal, right.getHead().resultVal, + ctx); + default: Errors.inst.printError(EK_EVAL_UNBIN, binOp.toString()); return new Tree<>(FAIL(ast)); } } - private static ITree<Node> evaluateStringBinary(final Token.Type op, final EvaluatorResult left, - final EvaluatorResult right, final Context ctx) { + private static ITree<Node> evaluateStringBinary(final Token.Type op, + final EvaluatorResult left, + final EvaluatorResult right, final Context ctx) { if (left.type != STRING) { Errors.inst.printError(EK_EVAL_INVSTRING, left.type.toString()); return new Tree<>(FAIL(left)); @@ -307,7 +326,9 @@ public class Evaluator { } final String strung = right.stringVal; - return new Tree<>(new Node(Node.Type.RESULT, new EvaluatorResult(STRING, strang + strung))); + return new Tree<>(new Node(Node.Type.RESULT, new EvaluatorResult(STRING, + strang + strung))); + case STRREP: if (right.type != INT) { Errors.inst.printError(EK_EVAL_INVSTRING, right.type.toString()); @@ -316,18 +337,22 @@ public class Evaluator { String res = strang; final long count = right.intVal; + for (long i = 1; i < count; i++) { res += strang; } + return new Tree<>(new Node(Node.Type.RESULT, new EvaluatorResult(STRING, res))); + default: Errors.inst.printError(EK_EVAL_UNSTRING, op.toString()); return new Tree<>(FAIL()); } } - private static ITree<Node> evaluateDiceBinary(final Token.Type op, final EvaluatorResult left, - final EvaluatorResult right, final Context ctx) { + private static ITree<Node> evaluateDiceBinary(final Token.Type op, + final EvaluatorResult left, + final EvaluatorResult right, final Context ctx) { EvaluatorResult res = null; switch (op) { @@ -335,10 +360,10 @@ public class Evaluator { 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)); + new SimpleDie(left.diceVal.scalar, right.diceVal.scalar)); } else if (right.type == INT) { res = new EvaluatorResult(DICE, - new SimpleDie(left.diceVal.scalar, right.intVal)); + new SimpleDie(left.diceVal.scalar, right.intVal)); } else { Errors.inst.printError(EK_EVAL_INVDGROUP, right.type.toString()); return new Tree<>(FAIL(right)); @@ -346,7 +371,7 @@ public class Evaluator { } else if (left.type == INT) { if (right.type == DICE && !right.diceVal.isList) { res = new EvaluatorResult(DICE, - new SimpleDie(left.intVal, right.diceVal.scalar)); + new SimpleDie(left.intVal, right.diceVal.scalar)); } else if (right.type == INT) { res = new EvaluatorResult(DICE, new SimpleDie(left.intVal, right.intVal)); } else { @@ -357,6 +382,7 @@ public class Evaluator { 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()); @@ -366,9 +392,11 @@ public class Evaluator { return new Tree<>(FAIL(right)); } else { res = new EvaluatorResult(DICE, - new CompoundDie(left.diceVal.scalar, right.diceVal.scalar)); + 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()); @@ -378,9 +406,11 @@ public class Evaluator { return new Tree<>(FAIL(right)); } else { res = new EvaluatorResult(DICE, - new SimpleDieList(left.diceVal.scalar, right.diceVal.scalar)); + new SimpleDieList(left.diceVal.scalar, right.diceVal.scalar)); } + break; + default: Errors.inst.printError(EK_EVAL_UNDICE, op.toString()); return new Tree<>(FAIL()); @@ -389,8 +419,9 @@ public class Evaluator { return new Tree<>(new Node(Node.Type.RESULT, res)); } - private static ITree<Node> evaluateMathBinary(final Token.Type op, final EvaluatorResult left, - final EvaluatorResult right, final Context ctx) { + private static ITree<Node> evaluateMathBinary(final Token.Type op, + final EvaluatorResult left, + final EvaluatorResult right, final Context ctx) { if (left.type == STRING || right.type == STRING) { Errors.inst.printError(EK_EVAL_STRINGMATH); return new Tree<>(FAIL()); @@ -432,11 +463,13 @@ public class Evaluator { } res = new EvaluatorResult(DICE, new MathDie(MathDie.MathOp.ADD, left.diceVal.scalar, - right.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); @@ -450,11 +483,13 @@ public class Evaluator { } res = new EvaluatorResult(DICE, new MathDie(MathDie.MathOp.SUBTRACT, - left.diceVal.scalar, right.diceVal.scalar)); + 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); @@ -468,11 +503,13 @@ public class Evaluator { } res = new EvaluatorResult(DICE, new MathDie(MathDie.MathOp.MULTIPLY, - left.diceVal.scalar, right.diceVal.scalar)); + 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) { @@ -492,7 +529,9 @@ public class Evaluator { Errors.inst.printError(EK_EVAL_DIVDICE); return new Tree<>(FAIL()); } + break; + case IDIVIDE: if (left.type == INT) { if (right.intVal == 0) { @@ -512,7 +551,9 @@ public class Evaluator { Errors.inst.printError(EK_EVAL_DIVDICE); return new Tree<>(FAIL()); } + break; + default: Errors.inst.printError(EK_EVAL_UNMATH, op.toString()); return new Tree<>(FAIL()); @@ -528,15 +569,19 @@ public class Evaluator { 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.getStringLiteral((int) tk.intValue)); break; + default: Errors.inst.printError(EK_EVAL_UNTOK, tk.type.toString()); res = new EvaluatorResult(FAILURE); diff --git a/dice-lang/src/bjc/dicelang/EvaluatorResult.java b/dice-lang/src/bjc/dicelang/EvaluatorResult.java index d81612f..75bbb3f 100644 --- a/dice-lang/src/bjc/dicelang/EvaluatorResult.java +++ b/dice-lang/src/bjc/dicelang/EvaluatorResult.java @@ -52,19 +52,19 @@ public class EvaluatorResult { /** * The integer value of the result. */ - public long intVal; + public long intVal; /** * The float value of the result. */ - public double floatVal; + public double floatVal; /** * The dice value of the result. */ - public DieExpression diceVal; + public DieExpression diceVal; /** * The string value of the result. */ - public String stringVal; + public String stringVal; /** * Original node data @@ -196,14 +196,19 @@ public class EvaluatorResult { 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(); } diff --git a/dice-lang/src/bjc/dicelang/Node.java b/dice-lang/src/bjc/dicelang/Node.java index af26870..af69c8c 100644 --- a/dice-lang/src/bjc/dicelang/Node.java +++ b/dice-lang/src/bjc/dicelang/Node.java @@ -13,10 +13,10 @@ public class Node { 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 Token tokenVal; + public Token.Type operatorType; + public GroupType groupType; + public EvaluatorResult resultVal; public Node(final Type typ) { type = typ; @@ -52,13 +52,17 @@ public class Node { 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; } @@ -75,6 +79,7 @@ public class Node { 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 index 1029943..7e48f43 100644 --- a/dice-lang/src/bjc/dicelang/Parser.java +++ b/dice-lang/src/bjc/dicelang/Parser.java @@ -45,7 +45,8 @@ public class Parser { * * @return Whether or not the parse was successful. */ - public static boolean parseTokens(final IList<Token> tokens, final IList<ITree<Node>> results) { + public static boolean parseTokens(final IList<Token> tokens, + final IList<ITree<Node>> results) { final Deque<ITree<Node>> working = new LinkedList<>(); for (final Token tk : tokens) { @@ -54,11 +55,15 @@ public class Parser { case OBRACE: working.push(new Tree<>(new Node(OGROUP, tk))); break; + case CBRACKET: case CBRACE: final boolean sc = parseClosingGrouper(working, tk); + if (!sc) return false; + break; + case MULTIPLY: case DIVIDE: case IDIVIDE: @@ -76,6 +81,7 @@ public class Parser { handleBinaryNode(working, tk); break; + case ADD: case SUBTRACT: if (working.size() == 0) { @@ -92,7 +98,9 @@ public class Parser { } else { handleBinaryNode(working, tk); } + break; + case COERCE: case DICESCALAR: case DICEFUDGE: @@ -106,7 +114,9 @@ public class Parser { working.push(opNode); } + break; + case INT_LIT: case FLOAT_LIT: case STRING_LIT: @@ -114,6 +124,7 @@ public class Parser { case DICE_LIT: working.push(new Tree<>(new Node(TOKREF, tk))); break; + default: Errors.inst.printError(EK_PARSE_INVTOKEN, tk.type.toString()); return false; @@ -139,26 +150,31 @@ public class Parser { working.push(opNode); } - private static boolean parseClosingGrouper(final Deque<ITree<Node>> working, final Token tk) { + private static boolean parseClosingGrouper(final Deque<ITree<Node>> working, + final Token tk) { if (working.size() == 0) { Errors.inst.printError(EK_PARSE_NOCLOSE); return false; } ITree<Node> 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: Errors.inst.printError(EK_PARSE_UNCLOSE, tk.type.toString()); return false; } Token matching = null; + if (tk.type == CBRACKET) { matching = new Token(Token.Type.OBRACKET, tk.intValue); } else if (tk.type == CBRACE) { @@ -166,12 +182,14 @@ public class Parser { } final ITree<Node> 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 (final ITree<Node> ast : working) { System.out.println("Tree " + treeNo++ + ": " + ast.toString()); } diff --git a/dice-lang/src/bjc/dicelang/Shunter.java b/dice-lang/src/bjc/dicelang/Shunter.java index ffe730b..d9025c1 100644 --- a/dice-lang/src/bjc/dicelang/Shunter.java +++ b/dice-lang/src/bjc/dicelang/Shunter.java @@ -73,19 +73,19 @@ public class Shunter { /** * Precedence for math operators. */ - public final int MATH_PREC = 30; + public final int MATH_PREC = 30; /** * Precedence for dice operators. */ - public final int DICE_PREC = 20; + public final int DICE_PREC = 20; /** * Precedence for string operators. */ - public final int STR_PREC = 10; + public final int STR_PREC = 10; /** * Precedence for expression operators. */ - public final int EXPR_PREC = 0; + public final int EXPR_PREC = 0; /** * Create a new shunter. @@ -168,8 +168,9 @@ public class Shunter { return true; } - private boolean shuntToken(final Token tk, final Deque<Token> opStack, final Deque<Token> unaryStack, - final Deque<Token> currReturned, final Deque<Token> feed) { + private boolean shuntToken(final Token tk, final Deque<Token> opStack, + final Deque<Token> unaryStack, + final Deque<Token> currReturned, final Deque<Token> feed) { if (unaryStack.size() != 0) { if (isUnary(tk)) { unaryStack.add(tk); @@ -247,9 +248,11 @@ public class Shunter { case CPAREN: matching = new Token(OPAREN, tk.intValue); break; + case CBRACE: matching = new Token(OBRACE, tk.intValue); break; + default: Errors.inst.printError(EK_SHUNT_NOGROUP); return false; @@ -330,9 +333,13 @@ public class Shunter { final 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; @@ -342,7 +349,9 @@ public class Shunter { final 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; diff --git a/dice-lang/src/bjc/dicelang/Token.java b/dice-lang/src/bjc/dicelang/Token.java index 22df90b..8b6d12b 100644 --- a/dice-lang/src/bjc/dicelang/Token.java +++ b/dice-lang/src/bjc/dicelang/Token.java @@ -86,14 +86,18 @@ public class Token { 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(); } @@ -111,6 +115,7 @@ public class Token { case OBRACE: case OBRACKET: return intValue == otk.intValue; + default: return true; } @@ -122,6 +127,7 @@ public class Token { 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 index 3ca9a94..259661d 100644 --- a/dice-lang/src/bjc/dicelang/Tokenizer.java +++ b/dice-lang/src/bjc/dicelang/Tokenizer.java @@ -89,6 +89,7 @@ public class Tokenizer { case '}': tk = tokenizeGrouping(token); break; + default: tk = tokenizeLiteral(token, stringLts); } @@ -105,21 +106,27 @@ public class Tokenizer { 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; @@ -129,9 +136,12 @@ public class Tokenizer { return tk; } - private final Pattern hexadecimalMatcher = Pattern.compile("\\A[\\-\\+]?0x[0-9A-Fa-f]+\\Z"); - private final Pattern flexadecimalMatcher = Pattern.compile("\\A[\\-\\+]?[0-9][0-9A-Za-z]+B\\d{1,2}\\Z"); - private final Pattern stringLitMatcher = Pattern.compile("\\AstringLiteral(\\d+)\\Z"); + private final Pattern hexadecimalMatcher = + Pattern.compile("\\A[\\-\\+]?0x[0-9A-Fa-f]+\\Z"); + private final Pattern flexadecimalMatcher = + Pattern.compile("\\A[\\-\\+]?[0-9][0-9A-Za-z]+B\\d{1,2}\\Z"); + private final Pattern stringLitMatcher = + Pattern.compile("\\AstringLiteral(\\d+)\\Z"); private Token tokenizeLiteral(final String token, final IMap<String, String> stringLts) { Token tk = Token.NIL_TOKEN; diff --git a/dice-lang/src/bjc/dicelang/dice/CompoundDie.java b/dice-lang/src/bjc/dicelang/dice/CompoundDie.java index 7cd8fcf..a81322c 100644 --- a/dice-lang/src/bjc/dicelang/dice/CompoundDie.java +++ b/dice-lang/src/bjc/dicelang/dice/CompoundDie.java @@ -9,8 +9,8 @@ public class CompoundDie implements Die { /*
* The dice that form this die
*/
- private final Die left;
- private final Die right;
+ private final Die left;
+ private final Die right;
/**
* Create a new compound die.
diff --git a/dice-lang/src/bjc/dicelang/dice/CompoundingDie.java b/dice-lang/src/bjc/dicelang/dice/CompoundingDie.java index 73d910a..1bd478f 100644 --- a/dice-lang/src/bjc/dicelang/dice/CompoundingDie.java +++ b/dice-lang/src/bjc/dicelang/dice/CompoundingDie.java @@ -13,8 +13,8 @@ import java.util.function.Predicate; public class CompoundingDie implements Die {
private final Die source;
- private final Predicate<Long> compoundOn;
- private final String compoundPattern;
+ private final Predicate<Long> compoundOn;
+ private final String compoundPattern;
/**
* Create a new compounding die with no pattern.
diff --git a/dice-lang/src/bjc/dicelang/dice/DiceBox.java b/dice-lang/src/bjc/dicelang/dice/DiceBox.java index c956977..afb2ea3 100644 --- a/dice-lang/src/bjc/dicelang/dice/DiceBox.java +++ b/dice-lang/src/bjc/dicelang/dice/DiceBox.java @@ -41,6 +41,7 @@ public class DiceBox { final String[] dieParts = expString.split("d"); final long right = Long.parseLong(dieParts[1]); + if (dieParts[0].equals("")) { /* * Handle short-form expressions. @@ -131,16 +132,18 @@ public class DiceBox { * * This is just a number. */ - private static final String scalarDie = "[\\+\\-]?\\d+sd"; - private static final Pattern scalarDiePattern = Pattern.compile("\\A" + scalarDie + "\\Z"); + private static final String scalarDie = "[\\+\\-]?\\d+sd"; + private static final Pattern scalarDiePattern = Pattern.compile("\\A" + + scalarDie + "\\Z"); /* * Defines a simple die. * * This is a group of one or more dice of the same size. */ - private static final String simpleDie = "(?:\\d+)?d\\d+"; - private static final Pattern simpleDiePattern = Pattern.compile("\\A" + simpleDie + "\\Z"); + private static final String simpleDie = "(?:\\d+)?d\\d+"; + private static final Pattern simpleDiePattern = Pattern.compile("\\A" + + simpleDie + "\\Z"); /* * Defines a fudge die. @@ -148,24 +151,28 @@ public class DiceBox { * This is like a simple die, but all the die give -1, 0, or 1 as * results. */ - private static final String fudgeDie = "(?:\\d+)?dF"; - private static final Pattern fudgeDiePattern = Pattern.compile("\\A" + fudgeDie + "\\Z"); + private static final String fudgeDie = "(?:\\d+)?dF"; + private static final Pattern fudgeDiePattern = Pattern.compile("\\A" + fudgeDie + + "\\Z"); /* * Defines a compound die. * * This is like using two d10's to simulate a d100 */ - private static final String compoundDie = simpleDie + "c(?:(?:" + simpleDie + ")|(?:\\d+))"; - private static final Pattern compoundDiePattern = Pattern.compile("\\A" + compoundDie + "\\Z"); + private static final String compoundDie = simpleDie + "c(?:(?:" + + simpleDie + ")|(?:\\d+))"; + private static final Pattern compoundDiePattern = Pattern.compile("\\A" + + compoundDie + "\\Z"); /* * Defines a compound group. * * This is used for forming die list type expressions. */ - private static final String compoundGroup = "(?:(?:" + scalarDie + ")|(?:" + simpleDie + ")|(?:" + compoundDie - + ")|(?:" + fudgeDie + "))"; + private static final String compoundGroup = "(?:(?:" + scalarDie + ")|(?:" + simpleDie + + ")|(?:" + compoundDie + + ")|(?:" + fudgeDie + "))"; /* * Defines a compounding die. @@ -173,8 +180,10 @@ public class DiceBox { * This is like an exploding die, but is a single die, not a group of * them. */ - private static final String compoundingDie = compoundGroup + "!!" + comparePoint; - private static final Pattern compoundingDiePattern = Pattern.compile("\\A" + compoundingDie + "\\Z"); + private static final String compoundingDie = compoundGroup + "!!" + + comparePoint; + private static final Pattern compoundingDiePattern = Pattern.compile("\\A" + + compoundingDie + "\\Z"); /* * Defines an exploding die. @@ -182,8 +191,10 @@ public class DiceBox { * This is a die that you reroll the component of if it meets a certain * condition. */ - private static final String explodingDie = compoundGroup + "!" + comparePoint; - private static final Pattern explodingDiePattern = Pattern.compile("\\A" + explodingDie + "\\Z"); + private static final String explodingDie = compoundGroup + "!" + + comparePoint; + private static final Pattern explodingDiePattern = Pattern.compile("\\A" + + explodingDie + "\\Z"); /* * Defines a penetrating die. @@ -191,16 +202,19 @@ public class DiceBox { * This is like an exploding die, but the exploded result gets a -1 * penalty. */ - private static final String penetratingDie = compoundGroup + "!" + comparePoint; - private static final Pattern penetratingDiePattern = Pattern.compile("\\A" + penetratingDie + "\\Z"); + private static final String penetratingDie = compoundGroup + "!" + + comparePoint; + private static final Pattern penetratingDiePattern = Pattern.compile("\\A" + + penetratingDie + "\\Z"); /* * Defines a die list. * * This is an array of dice of the specified size. */ - private static final String diceList = compoundGroup + "dl" + compoundGroup; - private static final Pattern diceListPattern = Pattern.compile("\\A" + diceList + "\\Z"); + private static final String diceList = compoundGroup + "dl" + compoundGroup; + private static final Pattern diceListPattern = Pattern.compile("\\A" + diceList + + "\\Z"); /** * Check if a given string is a valid die expression. @@ -239,10 +253,13 @@ public class DiceBox { 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/DieExpression.java b/dice-lang/src/bjc/dicelang/dice/DieExpression.java index b114da6..edf7684 100644 --- a/dice-lang/src/bjc/dicelang/dice/DieExpression.java +++ b/dice-lang/src/bjc/dicelang/dice/DieExpression.java @@ -16,11 +16,11 @@ public class DieExpression { /** * The scalar value in this expression, if there is one. */ - public Die scalar; + public Die scalar; /** * The list value in this expression, if there is one. */ - public DieList list; + public DieList list; /** * Create a scalar die expression. diff --git a/dice-lang/src/bjc/dicelang/dice/ExplodingDice.java b/dice-lang/src/bjc/dicelang/dice/ExplodingDice.java index 15d6572..7036f32 100644 --- a/dice-lang/src/bjc/dicelang/dice/ExplodingDice.java +++ b/dice-lang/src/bjc/dicelang/dice/ExplodingDice.java @@ -21,9 +21,9 @@ public class ExplodingDice implements DieList { /*
* The conditions for exploding.
*/
- private final Predicate<Long> explodeOn;
- private final String explodePattern;
- private final boolean explodePenetrates;
+ private final Predicate<Long> explodeOn;
+ private final String explodePattern;
+ private final boolean explodePenetrates;
/**
* Create a new exploding die.
@@ -48,7 +48,8 @@ public class ExplodingDice implements DieList { * Whether or not for explosions to penetrate (-1 to
* exploded die).
*/
- public ExplodingDice(final Die src, final Predicate<Long> explode, final boolean penetrate) {
+ public ExplodingDice(final Die src, final Predicate<Long> explode,
+ final boolean penetrate) {
this(src, explode, null, penetrate);
}
@@ -65,7 +66,8 @@ public class ExplodingDice implements DieList { * @param patt
* The string the condition came from, for printing.
*/
- public ExplodingDice(final Die src, final Predicate<Long> explode, final String patt, final boolean penetrate) {
+ public ExplodingDice(final Die src, final Predicate<Long> explode, final String patt,
+ final boolean penetrate) {
source = src;
explodeOn = explode;
explodePattern = patt;
@@ -95,6 +97,7 @@ public class ExplodingDice implements DieList { if (explodePenetrates) {
oldRes -= 1;
}
+
resList.add(oldRes);
}
@@ -102,6 +105,7 @@ public class ExplodingDice implements DieList { newRes[0] = res;
int i = 1;
+
for (final long rll : resList) {
newRes[i] = rll;
i += 1;
diff --git a/dice-lang/src/bjc/dicelang/dice/MathDie.java b/dice-lang/src/bjc/dicelang/dice/MathDie.java index 5feb193..1984581 100644 --- a/dice-lang/src/bjc/dicelang/dice/MathDie.java +++ b/dice-lang/src/bjc/dicelang/dice/MathDie.java @@ -32,10 +32,13 @@ public class MathDie implements Die { switch (this) { case ADD: return "+"; + case SUBTRACT: return "-"; + case MULTIPLY: return "*"; + default: return this.name(); } @@ -44,8 +47,8 @@ public class MathDie implements Die { private final MathDie.MathOp type; - private final Die left; - private final Die right; + private final Die left; + private final Die right; /** * Create a new math die. @@ -75,10 +78,13 @@ public class MathDie implements Die { switch (type) { case ADD: return lft + rght; + case SUBTRACT: return lft - rght; + case MULTIPLY: return lft * rght; + default: return 0; } diff --git a/dice-lang/src/bjc/dicelang/dice/SimpleDie.java b/dice-lang/src/bjc/dicelang/dice/SimpleDie.java index 5610535..60c5d53 100644 --- a/dice-lang/src/bjc/dicelang/dice/SimpleDie.java +++ b/dice-lang/src/bjc/dicelang/dice/SimpleDie.java @@ -7,8 +7,8 @@ package bjc.dicelang.dice; * */ public class SimpleDie implements Die { - private final Die numDice; - private final Die diceSize; + private final Die numDice; + private final Die diceSize; /** * Create a new dice group. diff --git a/dice-lang/src/bjc/dicelang/dice/SimpleDieList.java b/dice-lang/src/bjc/dicelang/dice/SimpleDieList.java index f382361..84896ea 100644 --- a/dice-lang/src/bjc/dicelang/dice/SimpleDieList.java +++ b/dice-lang/src/bjc/dicelang/dice/SimpleDieList.java @@ -7,8 +7,8 @@ package bjc.dicelang.dice; * */ public class SimpleDieList implements DieList { - private final Die numDice; - private final Die size; + private final Die numDice; + private final Die size; /** * Create a new list of dice. diff --git a/dice-lang/src/bjc/dicelang/expr/Parser.java b/dice-lang/src/bjc/dicelang/expr/Parser.java index 90a6b38..b3f83a4 100644 --- a/dice-lang/src/bjc/dicelang/expr/Parser.java +++ b/dice-lang/src/bjc/dicelang/expr/Parser.java @@ -52,6 +52,7 @@ public class Parser { */ final Token[] infixTokens = lex.lexString(ln, toks); System.out.println("Lexed tokens: "); + for (final Token tok : infixTokens) { System.out.println("\t" + tok); } @@ -60,9 +61,11 @@ public class Parser { * Print out infix expression. */ System.out.print("Lexed expression: "); + for (final Token tok : infixTokens) { System.out.print(tok.toExpr() + " "); } + System.out.println(); System.out.println(); @@ -71,6 +74,7 @@ public class Parser { */ final Token[] postfixTokens = Shunter.shuntTokens(infixTokens); System.out.println("Lexed tokens: "); + for (final Token tok : postfixTokens) { System.out.println("\t" + tok); } @@ -79,14 +83,17 @@ public class Parser { * Print out postfix tokens. */ System.out.print("Shunted expression: "); + for (final Token tok : postfixTokens) { System.out.print(tok.toExpr() + " "); } + System.out.println(); System.out.println(); final FunctionalList<Token> tokList = new FunctionalList<>(Arrays.asList(postfixTokens)); - final ITree<Token> ast = TreeConstructor.constructTree(tokList, tok -> tok.typ.isOperator); + final ITree<Token> ast = TreeConstructor.constructTree(tokList, + tok -> tok.typ.isOperator); /* * Print the tree, then the canonical expression for it. diff --git a/dice-lang/src/bjc/dicelang/expr/Shunter.java b/dice-lang/src/bjc/dicelang/expr/Shunter.java index 19b30c3..3e49356 100644 --- a/dice-lang/src/bjc/dicelang/expr/Shunter.java +++ b/dice-lang/src/bjc/dicelang/expr/Shunter.java @@ -41,6 +41,7 @@ public class Shunter { int leftPriority = tok.typ.operatorPriority; int rightPriority; + if (curOp == null) { rightPriority = 0; } else { diff --git a/dice-lang/src/bjc/dicelang/expr/Token.java b/dice-lang/src/bjc/dicelang/expr/Token.java index d7fc0e2..1a506bf 100644 --- a/dice-lang/src/bjc/dicelang/expr/Token.java +++ b/dice-lang/src/bjc/dicelang/expr/Token.java @@ -70,18 +70,25 @@ public class Token { switch (typ) { case ADD: return "+"; + case SUBTRACT: return "-"; + case MULTIPLY: return "*"; + case DIVIDE: return "/"; + case VREF: return tks.symbolTable.get(intValue); + case OPAREN: return "("; + case CPAREN: return ")"; + default: return "???"; } diff --git a/dice-lang/src/bjc/dicelang/expr/TokenType.java b/dice-lang/src/bjc/dicelang/expr/TokenType.java index fa20813..d88283e 100644 --- a/dice-lang/src/bjc/dicelang/expr/TokenType.java +++ b/dice-lang/src/bjc/dicelang/expr/TokenType.java @@ -44,11 +44,11 @@ public enum TokenType { /** * Whether or not this type of token is an operator. */ - public final boolean isOperator; + public final boolean isOperator; /** * The priority of this operator, if it is one. */ - public final int operatorPriority; + public final int operatorPriority; private TokenType(final int num, final boolean isOp, final int priority) { nVal = num; diff --git a/dice-lang/src/bjc/dicelang/scl/StreamControlEngine.java b/dice-lang/src/bjc/dicelang/scl/StreamControlEngine.java index ac9e880..b490217 100644 --- a/dice-lang/src/bjc/dicelang/scl/StreamControlEngine.java +++ b/dice-lang/src/bjc/dicelang/scl/StreamControlEngine.java @@ -174,8 +174,8 @@ public class StreamControlEngine { } } - private static final Map<String, Token.Type> litTokens; - private static final Map<String, Token.Type> builtinWords; + private static final Map<String, Token.Type> litTokens; + private static final Map<String, Token.Type> builtinWords; static { litTokens = new HashMap<>(); @@ -242,21 +242,31 @@ public class StreamControlEngine { switch (tok.type) { case SQUOTE: i = handleSingleQuote(i, tokens); + if (i == -1) return false; + break; + case OBRACKET: i = handleDelim(i, tokens, "]"); + if (i == -1) return false; + break; + case OBRACE: i = handleDelim(i, tokens, "}"); + if (i == -1) return false; + final Token brak = curStack.pop(); curStack.push(new Token(ARRAY, brak.tokenVals)); break; + case WORD: handleWord(tok); break; + default: curStack.push(tok); break; @@ -273,51 +283,80 @@ public class StreamControlEngine { case NEWSTREAM: eng.newStream(); break; + case LEFTSTREAM: succ = eng.leftStream(); + if (!succ) return false; + break; + case RIGHTSTREAM: succ = eng.rightStream(); + if (!succ) return false; + break; + case DELETESTREAM: succ = eng.deleteStream(); + if (!succ) return false; + break; + case MERGESTREAM: succ = eng.mergeStream(); + if (!succ) return false; + break; + case MAKEARRAY: succ = makeArray(); + if (!succ) return false; + break; + case MAKEEXEC: succ = toggleExec(true); + if (!succ) return false; + break; + case MAKEUNEXEC: succ = toggleExec(false); + if (!succ) return false; + break; + case STACKCOUNT: curStack.push(new Token(ILIT, curStack.size())); break; + case STACKEMPTY: curStack.push(new Token(BLIT, curStack.empty())); break; + case DROP: if (curStack.size() == 0) { Errors.inst.printError(EK_SCL_SUNDERFLOW, tk.tokenVal.type.toString()); return false; } + curStack.drop(); break; + case NDROP: succ = handleNDrop(); + if (!succ) return false; + break; + case NIP: if (curStack.size() < 2) { Errors.inst.printError(EK_SCL_SUNDERFLOW, tk.tokenVal.type.toString()); @@ -326,10 +365,14 @@ public class StreamControlEngine { curStack.nip(); break; + case NNIP: succ = handleNNip(); + if (!succ) return false; + break; + default: Errors.inst.printError(EK_SCL_UNWORD, tk.tokenVal.type.toString()); return false; @@ -420,10 +463,12 @@ public class StreamControlEngine { final IList<Token> toks = new FunctionalList<>(); int n = i + 1; + if (n >= tokens.length) { Errors.inst.printError(EK_SCL_MMQUOTE); return -1; } + String tok = tokens[n]; while (!tok.equals(delim)) { @@ -432,31 +477,43 @@ public class StreamControlEngine { switch (ntok.type) { case SQUOTE: n = handleSingleQuote(n, tokens); + if (n == -1) return -1; + toks.add(curStack.pop()); break; + case OBRACKET: n = handleDelim(n, tokens, "]"); + if (n == -1) return -1; + toks.add(curStack.pop()); break; + case OBRACE: n = handleDelim(i, tokens, "}"); + if (n == -1) return -1; + final Token brak = curStack.pop(); toks.add(new Token(ARRAY, brak.tokenVals)); break; + default: toks.add(ntok); } + /* * Move to the next token */ n += 1; + if (n >= tokens.length) { Errors.inst.printError(EK_SCL_MMQUOTE); return -1; } + tok = tokens[n]; } @@ -474,10 +531,12 @@ public class StreamControlEngine { final StringBuilder sb = new StringBuilder(); int n = i + 1; + if (n >= tokens.length) { Errors.inst.printError(EK_SCL_MMQUOTE); return -1; } + String tok = tokens[n]; while (!tok.equals("'")) { @@ -494,10 +553,12 @@ public class StreamControlEngine { * Move to the next token */ n += 1; + if (n >= tokens.length) { Errors.inst.printError(EK_SCL_MMQUOTE); return -1; } + tok = tokens[n]; } diff --git a/dice-lang/src/bjc/dicelang/scl/StreamEngine.java b/dice-lang/src/bjc/dicelang/scl/StreamEngine.java index 4717eaa..f1abbdc 100644 --- a/dice-lang/src/bjc/dicelang/scl/StreamEngine.java +++ b/dice-lang/src/bjc/dicelang/scl/StreamEngine.java @@ -31,8 +31,8 @@ public class StreamEngine { /* * Our streams. */ - Tape<IList<String>> streams; - IList<String> currStream; + Tape<IList<String>> streams; + IList<String> currStream; /* * Saved streams @@ -210,26 +210,42 @@ public class StreamEngine { case '+': newStream(); break; + case '>': succ = rightStream(); + if (!succ) return false; + break; + case '<': succ = leftStream(); + if (!succ) return false; + break; + case '-': succ = deleteStream(); + if (!succ) return false; + break; + case 'M': succ = mergeStream(); + if (!succ) return false; + break; + case 'L': succ = scleng.runProgram(currStream.toArray(new String[0])); + if (!succ) return false; + break; + default: Errors.inst.printError(EK_STRM_INVCOM, tk); return false; |
