summaryrefslogtreecommitdiff
path: root/dice-lang/src/bjc/dicelang
diff options
context:
space:
mode:
authorBenjamin J. Culkin <bjculkin@mix.wvu.edu>2017-10-09 16:02:10 -0300
committerBenjamin J. Culkin <bjculkin@mix.wvu.edu>2017-10-09 16:02:10 -0300
commitf028ea6dc555fc5192a96b00b8e96e90dbf6de55 (patch)
tree4b2a28ecbeb30095b50e6e9e8ac8b98fa8ddc79e /dice-lang/src/bjc/dicelang
parentbe4675f9512060aa85b1e0a4f223208b51b55812 (diff)
TODO tagging
Diffstat (limited to 'dice-lang/src/bjc/dicelang')
-rw-r--r--dice-lang/src/bjc/dicelang/CLIArgsParser.java41
-rw-r--r--dice-lang/src/bjc/dicelang/CompilerTweaker.java8
-rw-r--r--dice-lang/src/bjc/dicelang/Define.java43
-rw-r--r--dice-lang/src/bjc/dicelang/DiceLangConsole.java44
-rw-r--r--dice-lang/src/bjc/dicelang/DiceLangEngine.java90
-rw-r--r--dice-lang/src/bjc/dicelang/Evaluator.java172
-rw-r--r--dice-lang/src/bjc/dicelang/EvaluatorResult.java6
-rw-r--r--dice-lang/src/bjc/dicelang/Node.java11
-rw-r--r--dice-lang/src/bjc/dicelang/Parser.java34
-rw-r--r--dice-lang/src/bjc/dicelang/Shunter.java112
-rw-r--r--dice-lang/src/bjc/dicelang/Token.java4
-rw-r--r--dice-lang/src/bjc/dicelang/Tokenizer.java10
-rw-r--r--dice-lang/src/bjc/dicelang/dice/DiceBox.java30
-rw-r--r--dice-lang/src/bjc/dicelang/dice/DieExpression.java19
-rw-r--r--dice-lang/src/bjc/dicelang/dice/ExplodingDice.java31
-rw-r--r--dice-lang/src/bjc/dicelang/dice/FudgeDie.java5
-rw-r--r--dice-lang/src/bjc/dicelang/dice/MathDie.java20
-rw-r--r--dice-lang/src/bjc/dicelang/dice/ScalarDie.java5
-rw-r--r--dice-lang/src/bjc/dicelang/dice/SimpleDie.java12
-rw-r--r--dice-lang/src/bjc/dicelang/dice/SimpleDieList.java12
-rw-r--r--dice-lang/src/bjc/dicelang/expr/Ezpr.java4
-rw-r--r--dice-lang/src/bjc/dicelang/expr/Lexer.java25
-rw-r--r--dice-lang/src/bjc/dicelang/expr/Parser.java108
-rw-r--r--dice-lang/src/bjc/dicelang/expr/Shunter.java26
-rw-r--r--dice-lang/src/bjc/dicelang/expr/Token.java32
-rw-r--r--dice-lang/src/bjc/dicelang/expr/TokenType.java61
-rw-r--r--dice-lang/src/bjc/dicelang/expr/Tokens.java50
-rw-r--r--dice-lang/src/bjc/dicelang/scl/StreamControlConsole.java38
-rw-r--r--dice-lang/src/bjc/dicelang/scl/StreamControlEngine.java216
-rw-r--r--dice-lang/src/bjc/dicelang/scl/StreamEngine.java34
-rw-r--r--dice-lang/src/bjc/dicelang/util/ResourceLoader.java5
31 files changed, 645 insertions, 663 deletions
diff --git a/dice-lang/src/bjc/dicelang/CLIArgsParser.java b/dice-lang/src/bjc/dicelang/CLIArgsParser.java
index a1f822c..54061bd 100644
--- a/dice-lang/src/bjc/dicelang/CLIArgsParser.java
+++ b/dice-lang/src/bjc/dicelang/CLIArgsParser.java
@@ -47,97 +47,79 @@ public class CLIArgsParser {
for (int i = 0; i < args.length; i++) {
final String arg = args[i];
+ /*
+ * @TODO 10/08/17 Ben Culkin :CLIArgRefactor
+ * Use whatever library gets added to BJC-Utils for
+ * this, and extend these to do more things.
+ */
switch (arg) {
case "-d":
case "--debug":
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
- */
+ /* @NOTE
+ * Not yet implemented.
+ */
default:
Errors.inst.printError(EK_CLI_UNARG, arg);
return false;
@@ -147,8 +129,11 @@ public class CLIArgsParser {
return true;
}
+ /* Handle parsing a simple define. */
private static int simpleDefine(final int i, final String[] args,
final DiceLangEngine eng) {
+ /* :DefineRefactor */
+
if (i >= args.length - 1) {
Errors.inst.printError(EK_CLI_MISARG, "define");
return -1;
@@ -177,6 +162,7 @@ public class CLIArgsParser {
return i + 2;
}
+ /* Load a series of defines from a file. */
private static int defineFile(final int i, final String[] args,
final DiceLangEngine eng) {
if (i >= args.length - 1) {
@@ -223,8 +209,7 @@ public class CLIArgsParser {
private static Define parseDefine(final String ln) {
final Define res = null;
- // @TODO move this functionality from DiceLangConsole to some
- // common ground where it can be used by both functions
+ /* :DefineRefactor */
return res;
}
}
diff --git a/dice-lang/src/bjc/dicelang/CompilerTweaker.java b/dice-lang/src/bjc/dicelang/CompilerTweaker.java
index bb5cbde..1154be4 100644
--- a/dice-lang/src/bjc/dicelang/CompilerTweaker.java
+++ b/dice-lang/src/bjc/dicelang/CompilerTweaker.java
@@ -2,15 +2,17 @@ package bjc.dicelang;
import bjc.utils.parserutils.splitter.ConfigurableTokenSplitter;
+/*
+ * @TODO 10/09/17 Ben Culkin :CompilerTweaking
+ * Expand this to allow tweaking more things about the compiler.
+ */
/**
* Contains methods for customizing the DiceLang and SCL compilers.
*
* @author Ben Culkin
*/
public class CompilerTweaker {
- /*
- * Bits of the compiler necessary
- */
+ /* Bits of the compiler necessary */
private final DiceLangEngine eng;
private final ConfigurableTokenSplitter opExpander;
diff --git a/dice-lang/src/bjc/dicelang/Define.java b/dice-lang/src/bjc/dicelang/Define.java
index f4a8871..5524477 100644
--- a/dice-lang/src/bjc/dicelang/Define.java
+++ b/dice-lang/src/bjc/dicelang/Define.java
@@ -12,6 +12,10 @@ import java.util.regex.PatternSyntaxException;
import bjc.utils.data.CircularIterator;
+/*
+ * @TODO 10/09/17 Ben Culkin :DefineRefactor
+ * Consider replacing this with the defines package from BJC-Utils.
+ */
/**
* A regular expression based pre-processor define.
*
@@ -26,38 +30,34 @@ public class Define implements UnaryOperator<String>, Comparable<Define> {
*
*/
public static enum Type {
- /**
- * Match on lines.
- */
+ /** Match on lines. */
LINE,
- /**
- * Match on tokens.
- */
+ /** Match on tokens. */
TOKEN
}
- /**
- * The max amount of times to recur on expansions.
- */
+ /** The max amount of times to recur on expansions. */
public static int MAX_RECURS = 10;
- /**
- * The priority of this definition.
- */
+ /** The priority of this definition. */
public final int priority;
- /**
- * Whether or not this definition is in error.
- */
+ /** Whether or not this definition is in error. */
public final boolean inError;
+ /* Whether this define is recurring. */
private boolean doRecur;
+ /* Whether this define is applied multiple times per unit. */
private boolean subType;
+ /* The pattern that needs to match to apply this. */
private Pattern predicate;
+ /* The pattern to use to find everything to replace. */
private Pattern searcher;
+ /* The array of replacement strings to use. */
private Iterator<String> replacers;
+ /* The current replacement string to use. */
private String replacer;
/**
@@ -91,9 +91,7 @@ public class Define implements UnaryOperator<String>, Comparable<Define> {
doRecur = recur;
subType = isSub;
- /*
- * Only try to compile non-null predicates
- */
+ /* Only try to compile non-null predicates */
if (predicte != null) {
try {
predicate = Pattern.compile(predicte);
@@ -104,9 +102,7 @@ public class Define implements UnaryOperator<String>, Comparable<Define> {
}
}
- /*
- * Compile the search pattern
- */
+ /* Compile the search pattern */
try {
searcher = Pattern.compile(searchr);
} catch (final PatternSyntaxException psex) {
@@ -117,9 +113,7 @@ public class Define implements UnaryOperator<String>, Comparable<Define> {
inError = false;
- /*
- * Check whether or not we do sub-replacements
- */
+ /* Check whether or not we do sub-replacements */
if (subType) {
if (replacrs.iterator().hasNext()) {
replacers = new CircularIterator<>(replacrs, isCircular);
@@ -174,6 +168,7 @@ public class Define implements UnaryOperator<String>, Comparable<Define> {
return strang;
}
+ /* Apply a definition pass. */
private String doPass(final String tok) {
final Matcher searcherMatcher = searcher.matcher(tok);
diff --git a/dice-lang/src/bjc/dicelang/DiceLangConsole.java b/dice-lang/src/bjc/dicelang/DiceLangConsole.java
index ebf9b59..296874f 100644
--- a/dice-lang/src/bjc/dicelang/DiceLangConsole.java
+++ b/dice-lang/src/bjc/dicelang/DiceLangConsole.java
@@ -43,9 +43,7 @@ public class DiceLangConsole {
Terminal.setupTerminal();
}
- /**
- * Run the console.
- */
+ /** Run the console. */
public void run() {
/* Set up console. */
try {
@@ -55,6 +53,7 @@ public class DiceLangConsole {
return;
}
+ /* Print greeting. */
System.out.println("dice-lang v0.2");
String comm = null;
@@ -67,6 +66,10 @@ public class DiceLangConsole {
}
/* Run commands. */
+ /* @NOTE
+ * Should switch this to a do-while loop to reduce code
+ * duplication.
+ */
while (!comm.equals("quit") && !comm.equals("exit")) {
if (comm.startsWith("pragma")) {
/* Run pragmas. */
@@ -94,6 +97,7 @@ public class DiceLangConsole {
commandNumber += 1;
}
+ /* Read the next command. */
try {
comm = read.readLine(String.format("(%d) dice-lang> ", commandNumber));
} catch (final IOException ioex) {
@@ -103,6 +107,7 @@ public class DiceLangConsole {
}
}
+ /* Handle running pragmas. */
private boolean handlePragma(final String pragma) {
if (eng.debugMode) {
System.out.println("\tRaw pragma: " + pragma);
@@ -119,32 +124,29 @@ public class DiceLangConsole {
pragmaName = pragma.substring(0, firstIndex);
}
+ /* Run pragmas. */
/*
- * Run pragmas.
+ * @TODO 10/09/17 Ben Culkin :PragmaRefactor
+ * Swap to using something that makes it easier to add
+ * 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;
@@ -155,36 +157,30 @@ public class DiceLangConsole {
/* Run a help mode. */
private static boolean helpMode(final String pragma) {
+ /* Get the help topic. */
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);
}
-
/* Help always works */
return true;
}
@@ -226,48 +222,51 @@ public class DiceLangConsole {
return false;
}
+ /* Get the priority and define type. */
final int priority = Integer.parseInt(defineText.substring(0, firstIndex));
final String defineType = defineText.substring(firstIndex + 1, secondIndex);
Define.Type type;
boolean subMode = false;
+ /* Parse the define type. */
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;
}
+ /* Do we want this to be a recursive pattern? */
final boolean doRecur = defineText.substring(secondIndex + 1, thirdIndex)
.equalsIgnoreCase("true");
+ /* Do we want this pattern to have a guard? */
final boolean hasGuard = defineText.substring(thirdIndex + 1, fourthIndex)
.equalsIgnoreCase("true");
+ /* Do we want this pattern to use circular replacements. */
final boolean isCircular = defineText.substring(thirdIndex + 1, fourthIndex)
.equalsIgnoreCase("true");
+ /* The part of the string that contains patterns. */
final String pats = defineText.substring(fifthIndex + 1).trim();
final Matcher patMatcher = slashPattern.matcher(pats);
String guardPattern = null;
if (hasGuard) {
+ /* Grab the guard pattern. */
if (!patMatcher.find()) {
Errors.inst.printError(EK_CONS_INVDEFINE, "(no guard pattern)");
return false;
@@ -277,6 +276,7 @@ public class DiceLangConsole {
}
if (!patMatcher.find()) {
+ /* Grab the search pattern. */
Errors.inst.printError(EK_CONS_INVDEFINE, "(no search pattern)");
return false;
}
@@ -285,6 +285,7 @@ public class DiceLangConsole {
final List<String> replacePatterns = new LinkedList<>();
while (patMatcher.find()) {
+ /* Grab the replacer patterns. */
replacePatterns.add(patMatcher.group(1));
}
@@ -296,6 +297,7 @@ public class DiceLangConsole {
return false;
}
+ /* Add the define to the proper place. */
if (type == Define.Type.LINE) {
eng.addLineDefine(dfn);
} else {
diff --git a/dice-lang/src/bjc/dicelang/DiceLangEngine.java b/dice-lang/src/bjc/dicelang/DiceLangEngine.java
index 7b65f77..71e5ee8 100644
--- a/dice-lang/src/bjc/dicelang/DiceLangEngine.java
+++ b/dice-lang/src/bjc/dicelang/DiceLangEngine.java
@@ -34,6 +34,7 @@ import bjc.utils.parserutils.splitter.ConfigurableTokenSplitter;
* @author Ben Culkin
*/
public class DiceLangEngine {
+ /* Logger. */
private static final Logger LOG = Logger.getLogger(DiceLangEngine.class.getName());
/*
@@ -120,22 +121,21 @@ public class DiceLangEngine {
nextLiteral = 1;
/* Initial mode settings. */
- debugMode = true;
+ debugMode = true;
postfixMode = false;
- prefixMode = false;
- stepEval = false;
+ prefixMode = false;
+ stepEval = false;
/* Create components. */
+ shunt = new Shunter();
+ parsr = new Parser();
+
streamEng = new StreamEngine(this);
- shunt = new Shunter();
- tokenzer = new Tokenizer(this);
- parsr = new Parser();
- eval = new Evaluator(this);
+ tokenzer = new Tokenizer(this);
+ eval = new Evaluator(this);
}
- /**
- * Sort defns by priority.
- */
+ /** Sort defns by priority. */
public void sortDefns() {
lineDefns.sort(null);
tokenDefns.sort(null);
@@ -225,6 +225,10 @@ public class DiceLangEngine {
*/
public boolean runCommand(final String command) {
/* Preprocess the command into tokens */
+ /* @NOTE
+ * Instead of strings, this should maybe use a RawToken
+ * class or something.
+ */
final IList<String> preprocessedTokens = preprocessCommand(command);
if (preprocessedTokens == null) {
@@ -260,6 +264,10 @@ public class DiceLangEngine {
/* Apply token defns */
for (final Define dfn : tokenDefns.toIterable()) {
+ /* @NOTE
+ * What happens with a define that produces
+ * multiple tokens from one token?
+ */
newTok = dfn.apply(newTok);
}
@@ -273,9 +281,8 @@ public class DiceLangEngine {
if (tk == null) {
/* Ignore blank tokens */
continue;
- } else if (tk == Token.NIL_TOKEN)
+ } else if (tk == Token.NIL_TOKEN) {
/* Fail on bad tokens */
- {
return null;
} else {
lexedTokens.add(tk);
@@ -305,6 +312,7 @@ public class DiceLangEngine {
System.out.print(msg);
}
+ /* Only shunt if we're not in a special mode. */
if (!postfixMode && !prefixMode) {
/* Shunt the tokens */
shuntedTokens = new FunctionalList<>();
@@ -315,6 +323,11 @@ public class DiceLangEngine {
}
} else if (prefixMode) {
/* Reverse directional tokens */
+ /*
+ * @NOTE
+ * Merge these two operations into one iteration
+ * over the list?
+ */
preparedTokens.reverse();
shuntedTokens = preparedTokens.map(this::reverseToken);
}
@@ -328,8 +341,8 @@ public class DiceLangEngine {
/* Expand token groups */
final IList<Token> readyTokens = shuntedTokens.flatMap(tk -> {
if (tk.type == Token.Type.TOKGROUP ||
- tk.type == Token.Type.TAGOP ||
- tk.type == Token.Type.TAGOPR ) {
+ tk.type == Token.Type.TAGOP ||
+ tk.type == Token.Type.TAGOPR ) {
LOG.finer(String.format("Expanding token group to: %s\n", tk.tokenValues.toString()));
return tk.tokenValues;
} else {
@@ -350,28 +363,22 @@ public class DiceLangEngine {
/*
* Reverse orientation-sensitive tokens.
*
- * These are mostly just things like (, {, and [
+ * These are things like (, {, and [
*/
private Token reverseToken(final Token tk) {
switch (tk.type) {
case OBRACE:
return new Token(CBRACE, tk.intValue);
-
case OPAREN:
return new Token(CPAREN, tk.intValue);
-
case OBRACKET:
return new Token(CBRACKET, tk.intValue);
-
case CBRACE:
return new Token(OBRACE, tk.intValue);
-
case CPAREN:
return new Token(OPAREN, tk.intValue);
-
case CBRACKET:
return new Token(OBRACKET, tk.intValue);
-
default:
return tk;
}
@@ -386,13 +393,13 @@ public class DiceLangEngine {
/* Run the tokens through the stream engine */
final IList<String> streamToks = new FunctionalList<>();
- final boolean succ = streamEng.doStreams(command.split(" "), streamToks);
+ final boolean succ = streamEng.doStreams(command.split(" "),
+ streamToks);
if (!succ) {
return null;
}
- /* Apply line defns */
String newComm = ListUtils.collapseTokens(streamToks, " ");
if (debugMode) {
@@ -401,6 +408,7 @@ public class DiceLangEngine {
System.out.print(msg);
}
+ /* Apply line defns */
for (final Define dfn : lineDefns.toIterable()) {
newComm = dfn.apply(newComm);
}
@@ -412,7 +420,7 @@ public class DiceLangEngine {
}
/* Remove string literals. */
- final List<String> destringedParts = TokenUtils.removeDQuotedStrings(newComm);
+ final List<String> destringedParts = TokenUtils.removeDQuotedStrings(newComm);
final StringBuffer destringedCommand = new StringBuffer();
for (final String part : destringedParts) {
@@ -420,7 +428,7 @@ public class DiceLangEngine {
if (part.startsWith("\"") && part.endsWith("\"")) {
/* Get the actual string. */
final String litName = "stringLiteral" + nextLiteral;
- final String litVal = part.substring(1, part.length() - 1);
+ final String litVal = part.substring(1, part.length() - 1);
/*
* Insert the string with its escape sequences
@@ -458,7 +466,7 @@ public class DiceLangEngine {
}
/* Split the command into tokens */
- final String strang = destringedCommand.toString();
+ final String strang = destringedCommand.toString();
IList<String> tokens = FunctionalStringTokenizer.fromString(strang).toList();
/* Temporarily remove non-expanding tokens */
@@ -522,7 +530,11 @@ public class DiceLangEngine {
}
if (debugMode && stepEval) {
- /* @TODO fix stepEval */
+ /*
+ * @NOTE
+ * This is broken until stepwise top-down
+ * tree transforms are fixed.
+ */
int step = 1;
/* Evaluate it step by step */
@@ -556,9 +568,7 @@ public class DiceLangEngine {
System.out.printf(")");
}
- /*
- * Advance a step
- */
+ /* Advance a step */
System.out.println();
step += 1;
}
@@ -606,9 +616,7 @@ public class DiceLangEngine {
curBracedTokens = new FunctionalList<>();
} else if (tk.type == Token.Type.CBRACE && tk.intValue == 2) {
- /*
- * Close a preshunt group.
- */
+ /* Close a preshunt group. */
if (curBraceCount == 0) {
/*
* Error if there couldn't have been an
@@ -622,9 +630,7 @@ public class DiceLangEngine {
final IList<Token> preshuntTokens = new FunctionalList<>();
- /*
- * Shunt preshunt group.
- */
+ /* Shunt preshunt group. */
final boolean success = shunt.shuntTokens(curBracedTokens, preshuntTokens);
if (debugMode) {
@@ -647,7 +653,7 @@ public class DiceLangEngine {
} else {
/*
* Add the preshunt group to the token
- * stream..
+ * stream.
*/
preparedTokens.add(new Token(Token.Type.TOKGROUP, preshuntTokens));
}
@@ -665,9 +671,7 @@ public class DiceLangEngine {
}
if (curBraceCount > 0) {
- /*
- * There was an unclosed group.
- */
+ /* There was an unclosed group. */
Errors.inst.printError(EK_ENG_NOCLOSING);
return false;
}
@@ -675,10 +679,16 @@ public class DiceLangEngine {
return true;
}
+ /* Get a string literal from the string literal table. */
String getStringLiteral(final int key) {
return stringLits.get(key);
}
+ /* Add a string literal to the string literal table. */
+ /* @NOTE
+ * The string literal table should be abstracted into some kind of
+ * auto-numbered map thing.
+ */
void addStringLiteral(final int key, final String val) {
stringLits.put(key, val);
}
diff --git a/dice-lang/src/bjc/dicelang/Evaluator.java b/dice-lang/src/bjc/dicelang/Evaluator.java
index 0a583c8..10f7651 100644
--- a/dice-lang/src/bjc/dicelang/Evaluator.java
+++ b/dice-lang/src/bjc/dicelang/Evaluator.java
@@ -1,28 +1,5 @@
package bjc.dicelang;
-import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_DIVDICE;
-import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_DIVZERO;
-import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_INVBIN;
-import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_INVDCREATE;
-import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_INVDGROUP;
-import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_INVDICE;
-import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_INVNODE;
-import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_INVSTRING;
-import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_INVUNARY;
-import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_MISMATH;
-import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_STRINGMATH;
-import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_UNBIN;
-import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_UNDICE;
-import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_UNMATH;
-import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_UNSTRING;
-import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_UNTOK;
-import static bjc.dicelang.Errors.ErrorKey.EK_EVAL_UNUNARY;
-import static bjc.dicelang.EvaluatorResult.Type.DICE;
-import static bjc.dicelang.EvaluatorResult.Type.FAILURE;
-import static bjc.dicelang.EvaluatorResult.Type.FLOAT;
-import static bjc.dicelang.EvaluatorResult.Type.INT;
-import static bjc.dicelang.EvaluatorResult.Type.STRING;
-
import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedList;
@@ -40,6 +17,18 @@ import bjc.utils.data.TopDownTransformIterator;
import bjc.utils.data.TopDownTransformResult;
import bjc.utils.data.Tree;
+import static bjc.dicelang.Errors.ErrorKey.*;
+import static bjc.dicelang.EvaluatorResult.Type.DICE;
+import static bjc.dicelang.EvaluatorResult.Type.FAILURE;
+import static bjc.dicelang.EvaluatorResult.Type.FLOAT;
+import static bjc.dicelang.EvaluatorResult.Type.INT;
+import static bjc.dicelang.EvaluatorResult.Type.STRING;
+
+
+/* @TODO 10/09/17 Ben Culkin :EvaluatorSplit
+ * Type/sanity checking should be moved into a seperate stage, not part of
+ * evaluation.
+ */
/**
* Evaluate DiceLang ASTs
*
@@ -47,19 +36,26 @@ import bjc.utils.data.Tree;
*
*/
public class Evaluator {
+ /* The steps of type coercion. */
private static enum CoerceSteps {
INTEGER, DOUBLE;
}
+ /* The context during iteration. */
private static class Context {
public Consumer<Iterator<ITree<Node>>> thunk;
public boolean isDebug;
public Context() {
+ /* Empty block. */
}
}
+ /* @TODO 10/09/17 Ben Culkin :NodeFAIL
+ * These methods should be moved to Node.
+ */
+ /* Create a failing node. */
private static Node FAIL() {
return new Node(Node.Type.RESULT, new EvaluatorResult(FAILURE));
}
@@ -68,7 +64,6 @@ public class Evaluator {
return new Node(Node.Type.RESULT, new EvaluatorResult(FAILURE, orig));
}
- @SuppressWarnings("unused")
private static Node FAIL(final Node orig) {
return new Node(Node.Type.RESULT, new EvaluatorResult(FAILURE, orig));
}
@@ -78,6 +73,7 @@ public class Evaluator {
return new Node(Node.Type.RESULT, eres);
}
+ /* The engine we are connected to. */
private final DiceLangEngine eng;
/**
@@ -103,25 +99,26 @@ public class Evaluator {
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.
- *
+ * if stepping the iterator has side effects.
*/
while (itr.hasNext()) {
itr.next();
}
};
- final ITree<Node> res = comm.topDownTransform(this::pickEvaluationType,
- node -> this.evaluateNode(node, ctx));
+ /* The result. */
+ final ITree<Node> res = comm.topDownTransform(
+ this::pickEvaluationType,
+ node -> this.evaluateNode(node, ctx));
return res.getHead().resultVal;
}
- // FIXME Something's broken with step evaluation
- @SuppressWarnings("javadoc")
+ /* @NOTE
+ * This is broken until stepwise top-down transforms are fixed. */
public Iterator<ITree<Node>> stepDebug(final ITree<Node> comm) {
final Context ctx = new Context();
@@ -140,8 +137,8 @@ public class Evaluator {
case UNARYOP:
switch (nd.operatorType) {
case COERCE:
+ /* Coerce does special things to the tree. */
return TopDownTransformResult.RTRANSFORM;
-
default:
return TopDownTransformResult.PUSHDOWN;
}
@@ -156,19 +153,14 @@ 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));
@@ -177,31 +169,45 @@ public class Evaluator {
/* Evaluate a unary operator. */
private ITree<Node> evaluateUnaryOp(final ITree<Node> ast, final Context ctx) {
+ /* Unary operators only take one operand. */
if (ast.getChildrenCount() != 1) {
Errors.inst.printError(EK_EVAL_UNUNARY, Integer.toString(ast.getChildrenCount()));
return new Tree<>(FAIL(ast));
}
switch (ast.getHead().operatorType) {
- /* @TODO move coercing to its own class */
+ /*
+ * @TODO 10/09/17 Ben Culkin :CoerceRefactor :EvaluatorSplit
+ * Coercing should be moved to its own class, or at the
+ * very least its own method. When the evaluator splits,
+ * this node type'll be handled exclusively by the
+ * type-checker.
+ *
+ * Coerce also needs to be able to coerce things to
+ * dice and ratios (whenever they get added).
+ */
case COERCE:
final ITree<Node> toCoerce = ast.getChild(0);
final ITree<Node> retVal = new Tree<>(toCoerce.getHead());
final Deque<ITree<Node>> children = new LinkedList<>();
+ /* The current type we are coercing to. */
CoerceSteps curLevel = CoerceSteps.INTEGER;
for (int i = 0; i < toCoerce.getChildrenCount(); i++) {
final ITree<Node> child = toCoerce.getChild(i);
ITree<Node> nChild = null;
+ /* Tell our thunk we processed a node. */
if (ctx.isDebug) {
+ /* Evaluate each step of the child. */
final Iterator<ITree<Node>> nd = stepDebug(child);
for (; nd.hasNext(); nChild = nd.next()) {
ctx.thunk.accept(new SingleIterator<>(child));
}
} else {
+ /* Evaluate the child. */
nChild = new Tree<>(new Node(Node.Type.RESULT, evaluate(child)));
ctx.thunk.accept(new SingleIterator<>(nChild));
@@ -215,6 +221,7 @@ public class Evaluator {
final Node childNode = nChild.getHead();
final EvaluatorResult res = childNode.resultVal;
+ /* Move up to coercing to a float. */
if (res.type == FLOAT) {
curLevel = CoerceSteps.DOUBLE;
}
@@ -228,14 +235,12 @@ public class Evaluator {
switch (res.type) {
case INT:
+ /* Coerce ints to doubles if we need to. */
if (curLevel == CoerceSteps.DOUBLE) {
nd.resultVal = new EvaluatorResult(FLOAT, (double) res.intVal);
}
-
default:
- /*
- * Do nothing
- */
+ /* Do nothing */
break;
}
@@ -243,7 +248,6 @@ public class Evaluator {
}
return retVal;
-
case DICESCALAR:
final EvaluatorResult opr = ast.getChild(0).getHead().resultVal;
@@ -251,9 +255,8 @@ public class Evaluator {
Errors.inst.printError(EK_EVAL_INVDCREATE, opr.type.toString());
}
- return new Tree<>(new Node(Node.Type.RESULT,
- new EvaluatorResult(DICE, new ScalarDie(opr.intVal))));
-
+ final EvaluatorResult sres = new EvaluatorResult(DICE, new ScalarDie(opr.intVal));
+ return new Tree<>(new Node(Node.Type.RESULT, sres));
case DICEFUDGE:
final EvaluatorResult oprn = ast.getChild(0).getHead().resultVal;
@@ -261,57 +264,56 @@ public class Evaluator {
Errors.inst.printError(EK_EVAL_INVDCREATE, oprn.type.toString());
}
- return new Tree<>(new Node(Node.Type.RESULT,
- new EvaluatorResult(DICE, new FudgeDie(oprn.intVal))));
-
+ final EvaluatorResult fres = new EvaluatorResult(DICE, new ScalarDie(oprn.intVal));
+ return new Tree<>(new Node(Node.Type.RESULT, fres));
default:
Errors.inst.printError(EK_EVAL_INVUNARY, ast.getHead().operatorType.toString());
return new Tree<>(FAIL(ast));
}
}
+ /* Evaluate a binary operator. */
private static ITree<Node> evaluateBinaryOp(final ITree<Node> ast, final Context ctx) {
final Token.Type binOp = ast.getHead().operatorType;
+ /* Binary operators always have two children. */
if (ast.getChildrenCount() != 2) {
Errors.inst.printError(EK_EVAL_INVBIN, Integer.toString(ast.getChildrenCount()),
- ast.toString());
+ ast.toString());
return new Tree<>(FAIL(ast));
}
- final ITree<Node> left = ast.getChild(0);
+ final ITree<Node> left = ast.getChild(0);
final ITree<Node> right = ast.getChild(1);
+ final EvaluatorResult leftRes = left.getHead().resultVal;
+ final EvaluatorResult rightRes = right.getHead().resultVal;
+
switch (binOp) {
case ADD:
case SUBTRACT:
case MULTIPLY:
case DIVIDE:
case IDIVIDE:
- return evaluateMathBinary(binOp, left.getHead().resultVal, right.getHead().resultVal,
- ctx);
-
+ return evaluateMathBinary(binOp, leftRes, rightRes, ctx);
case DICEGROUP:
case DICECONCAT:
case DICELIST:
- return evaluateDiceBinary(binOp, left.getHead().resultVal, right.getHead().resultVal,
- ctx);
-
+ return evaluateDiceBinary(binOp, leftRes, rightRes, ctx);
case STRCAT:
case STRREP:
- return evaluateStringBinary(binOp, left.getHead().resultVal, right.getHead().resultVal,
- ctx);
-
+ return evaluateStringBinary(binOp, leftRes, rightRes, ctx);
default:
Errors.inst.printError(EK_EVAL_UNBIN, binOp.toString());
return new Tree<>(FAIL(ast));
}
}
+ /* Evaluate a binary operator on strings. */
private static ITree<Node> evaluateStringBinary(final Token.Type op,
- final EvaluatorResult left,
- final EvaluatorResult right, final Context ctx) {
+ 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));
@@ -327,9 +329,9 @@ public class Evaluator {
}
final String strung = right.stringVal;
- return new Tree<>(new Node(Node.Type.RESULT, new EvaluatorResult(STRING,
- strang + strung)));
+ final EvaluatorResult cres = new EvaluatorResult(STRING, strang + strung);
+ return new Tree<>(new Node(Node.Type.RESULT, cres));
case STRREP:
if (right.type != INT) {
Errors.inst.printError(EK_EVAL_INVSTRING, right.type.toString());
@@ -344,27 +346,35 @@ public class Evaluator {
}
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());
}
}
+ /* Evaluate dice binary operators. */
private static ITree<Node> evaluateDiceBinary(final Token.Type op,
- final EvaluatorResult left,
- final EvaluatorResult right, final Context ctx) {
+ final EvaluatorResult left,
+ final EvaluatorResult right, final Context ctx) {
EvaluatorResult res = null;
switch (op) {
+ /*
+ * @TODO 10/09/17 Ben Culkin :DiceSimplify
+ * Figure out some way to simplify this sort of
+ * thing.
+ */
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));
+ Die simple = new SimpleDie(
+ left.diceVal.scalar,
+ right.diceVal.scalar);
+
+ res = new EvaluatorResult(DICE, simple);
} 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));
@@ -372,7 +382,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 {
@@ -393,7 +403,7 @@ 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;
@@ -407,7 +417,7 @@ 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;
@@ -420,9 +430,10 @@ public class Evaluator {
return new Tree<>(new Node(Node.Type.RESULT, res));
}
+ /* Evaluate a binary math operator. */
private static ITree<Node> evaluateMathBinary(final Token.Type op,
- final EvaluatorResult left,
- final EvaluatorResult right, final Context ctx) {
+ 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());
@@ -464,7 +475,7 @@ 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);
}
@@ -484,7 +495,7 @@ 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);
}
@@ -504,7 +515,7 @@ 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);
}
@@ -563,6 +574,7 @@ public class Evaluator {
return new Tree<>(new Node(Node.Type.RESULT, res));
}
+ /* Evaluate a token reference. */
private ITree<Node> evaluateTokenRef(final Token tk, final Context ctx) {
EvaluatorResult res = null;
@@ -570,19 +582,15 @@ 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 75bbb3f..3ceee9b 100644
--- a/dice-lang/src/bjc/dicelang/EvaluatorResult.java
+++ b/dice-lang/src/bjc/dicelang/EvaluatorResult.java
@@ -6,6 +6,10 @@ import bjc.dicelang.dice.DieList;
import bjc.utils.data.ITree;
import bjc.utils.data.Tree;
+/*
+ * @TODO 10/09/17 Ben Culkin :EvalResultReorg
+ * Again, split it into seperate classes based off of the type.
+ */
/**
* The result from the evaluator.
*
@@ -213,4 +217,4 @@ public class EvaluatorResult {
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
index 0a57c54..4238cfc 100644
--- a/dice-lang/src/bjc/dicelang/Node.java
+++ b/dice-lang/src/bjc/dicelang/Node.java
@@ -1,6 +1,15 @@
package bjc.dicelang;
-@SuppressWarnings("javadoc")
+/*
+ * @TODO 10/09/17 Ben Culkin :NodeReorg
+ * Same thing, different class. Split into subclasses based off of the type
+ * values.
+ */
+/**
+ * Represents a node in the AST.
+ *
+ * @author Ben Culkin
+ */
public class Node {
public static enum Type {
ROOT, TOKREF, UNARYOP, BINOP, GROUP, OGROUP, RESULT
diff --git a/dice-lang/src/bjc/dicelang/Parser.java b/dice-lang/src/bjc/dicelang/Parser.java
index ddeccd2..0861e96 100644
--- a/dice-lang/src/bjc/dicelang/Parser.java
+++ b/dice-lang/src/bjc/dicelang/Parser.java
@@ -27,9 +27,7 @@ import bjc.utils.funcdata.IList;
*
*/
public class Parser {
- /**
- * Create a new parser.
- */
+ /** Create a new parser. */
public Parser() {
}
@@ -53,11 +51,13 @@ public class Parser {
switch (tk.type) {
case OBRACKET:
case OBRACE:
+ /* Parse opening delims. */
working.push(new Tree<>(new Node(OGROUP, tk)));
- break;
+ break;
case CBRACKET:
case CBRACE:
+ /* Parse closing delims. */
final boolean sc = parseClosingGrouper(working, tk);
if (!sc) {
@@ -65,7 +65,6 @@ public class Parser {
}
break;
-
case MULTIPLY:
case DIVIDE:
case IDIVIDE:
@@ -76,6 +75,7 @@ public class Parser {
case STRREP:
case LET:
case BIND:
+ /* Parse binary operator. */
if (working.size() < 2) {
Errors.inst.printError(EK_PARSE_BINARY);
return false;
@@ -83,16 +83,15 @@ public class Parser {
handleBinaryNode(working, tk);
break;
-
case ADD:
case SUBTRACT:
+ /* Handle binary/unary operators. */
if (working.size() == 0) {
Errors.inst.printError(EK_PARSE_UNOPERAND, tk.toString());
return false;
} else if (working.size() == 1) {
final ITree<Node> operand = working.pop();
-
- final ITree<Node> opNode = new Tree<>(new Node(UNARYOP, tk.type));
+ final ITree<Node> opNode = new Tree<>(new Node(UNARYOP, tk.type));
opNode.addChild(operand);
@@ -102,15 +101,15 @@ public class Parser {
}
break;
-
case COERCE:
case DICESCALAR:
case DICEFUDGE:
+ /* Handle unary operators. */
if (working.size() == 0) {
Errors.inst.printError(EK_PARSE_UNOPERAND, tk.toString());
} else {
final ITree<Node> operand = working.pop();
- final ITree<Node> opNode = new Tree<>(new Node(UNARYOP, tk.type));
+ final ITree<Node> opNode = new Tree<>(new Node(UNARYOP, tk.type));
opNode.addChild(operand);
@@ -118,21 +117,24 @@ public class Parser {
}
break;
-
case INT_LIT:
case FLOAT_LIT:
case STRING_LIT:
case VREF:
case DICE_LIT:
+ /* Handle literals. */
working.push(new Tree<>(new Node(TOKREF, tk)));
break;
-
default:
Errors.inst.printError(EK_PARSE_INVTOKEN, tk.type.toString());
return false;
}
}
+ /*
+ * Collect the remaining nodes as the roots of the trees in the
+ * AST forest.
+ */
for (final ITree<Node> ast : working) {
results.add(ast);
}
@@ -140,9 +142,10 @@ public class Parser {
return true;
}
+ /* Handle a binary operator. */
private static void handleBinaryNode(final Deque<ITree<Node>> working, final Token tk) {
final ITree<Node> right = working.pop();
- final ITree<Node> left = working.pop();
+ final ITree<Node> left = working.pop();
final ITree<Node> opNode = new Tree<>(new Node(BINOP, tk.type));
@@ -152,6 +155,7 @@ public class Parser {
working.push(opNode);
}
+ /* Parse a closing delimiter. */
private static boolean parseClosingGrouper(final Deque<ITree<Node>> working,
final Token tk) {
if (working.size() == 0) {
@@ -165,11 +169,9 @@ public class Parser {
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;
@@ -205,7 +207,7 @@ public class Parser {
childs.push(working.pop());
}
- // Discard opener
+ /* Discard opener */
working.pop();
for (final ITree<Node> child : childs) {
diff --git a/dice-lang/src/bjc/dicelang/Shunter.java b/dice-lang/src/bjc/dicelang/Shunter.java
index 407ca5a..9d63b41 100644
--- a/dice-lang/src/bjc/dicelang/Shunter.java
+++ b/dice-lang/src/bjc/dicelang/Shunter.java
@@ -1,32 +1,5 @@
package bjc.dicelang;
-import static bjc.dicelang.Errors.ErrorKey.EK_SHUNT_INVSEP;
-import static bjc.dicelang.Errors.ErrorKey.EK_SHUNT_NOGROUP;
-import static bjc.dicelang.Errors.ErrorKey.EK_SHUNT_NOTADJ;
-import static bjc.dicelang.Errors.ErrorKey.EK_SHUNT_NOTADV;
-import static bjc.dicelang.Errors.ErrorKey.EK_SHUNT_NOTASSOC;
-import static bjc.dicelang.Token.Type.ADD;
-import static bjc.dicelang.Token.Type.BIND;
-import static bjc.dicelang.Token.Type.CBRACE;
-import static bjc.dicelang.Token.Type.COERCE;
-import static bjc.dicelang.Token.Type.CPAREN;
-import static bjc.dicelang.Token.Type.DICECONCAT;
-import static bjc.dicelang.Token.Type.DICEGROUP;
-import static bjc.dicelang.Token.Type.DICELIST;
-import static bjc.dicelang.Token.Type.DIVIDE;
-import static bjc.dicelang.Token.Type.GROUPSEP;
-import static bjc.dicelang.Token.Type.IDIVIDE;
-import static bjc.dicelang.Token.Type.LET;
-import static bjc.dicelang.Token.Type.MULTIPLY;
-import static bjc.dicelang.Token.Type.OBRACE;
-import static bjc.dicelang.Token.Type.OPAREN;
-import static bjc.dicelang.Token.Type.STRCAT;
-import static bjc.dicelang.Token.Type.STRREP;
-import static bjc.dicelang.Token.Type.SUBTRACT;
-import static bjc.dicelang.Token.Type.TAGOP;
-import static bjc.dicelang.Token.Type.TAGOPR;
-import static bjc.dicelang.Token.Type.TOKGROUP;
-
import java.util.Deque;
import java.util.HashSet;
import java.util.LinkedList;
@@ -37,6 +10,13 @@ import bjc.utils.funcdata.FunctionalMap;
import bjc.utils.funcdata.IList;
import bjc.utils.funcdata.IMap;
+import static bjc.dicelang.Errors.ErrorKey.EK_SHUNT_INVSEP;
+import static bjc.dicelang.Errors.ErrorKey.EK_SHUNT_NOGROUP;
+import static bjc.dicelang.Errors.ErrorKey.EK_SHUNT_NOTADJ;
+import static bjc.dicelang.Errors.ErrorKey.EK_SHUNT_NOTADV;
+import static bjc.dicelang.Errors.ErrorKey.EK_SHUNT_NOTASSOC;
+import static bjc.dicelang.Token.Type.*;
+
/**
* Shunt a set of infix tokens to postfix tokens.
*
@@ -71,56 +51,56 @@ public class Shunter {
*/
Set<Token.Type> unaryGerunds;
- /**
- * Precedence for math operators.
- */
- public final int MATH_PREC = 30;
- /**
- * Precedence for dice operators.
- */
- public final int DICE_PREC = 20;
- /**
- * Precedence for string operators.
- */
- public final int STR_PREC = 10;
- /**
- * Precedence for expression operators.
- */
- public final int EXPR_PREC = 0;
+ /** Precedence for math operators. */
+ public final int MATH_PREC = 30;
+ /** Precedence for dice operators. */
+ public final int DICE_PREC = 20;
+ /** Precedence for string operators. */
+ public final int STR_PREC = 10;
+ /** Precedence for expression operators. */
+ public final int EXPR_PREC = 0;
- /**
- * Create a new shunter.
- */
+ /** Create a new shunter. */
public Shunter() {
+ /* Create op map. */
ops = new FunctionalMap<>();
+ /* Create association maps. */
rightAssoc = new HashSet<>();
- notAssoc = new HashSet<>();
+ notAssoc = new HashSet<>();
+ /* Create unary maps. */
unaryAdjectives = new HashSet<>();
- unaryAdverbs = new HashSet<>();
- unaryGerunds = new HashSet<>();
+ unaryAdverbs = new HashSet<>();
+ unaryGerunds = new HashSet<>();
+ /* Set up unary adverbs. */
unaryAdverbs.add(COERCE);
- ops.put(ADD, 0 + MATH_PREC);
+ /* Setup operators. */
+ /* Math operators. */
+ 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(IDIVIDE, 1 + MATH_PREC);
+ ops.put(DIVIDE, 1 + MATH_PREC);
+ /* Dice operators. */
ops.put(DICEGROUP, 0 + DICE_PREC);
ops.put(DICECONCAT, 1 + DICE_PREC);
ops.put(DICELIST, 2 + DICE_PREC);
+ /* String operators. */
ops.put(STRCAT, 0 + STR_PREC);
ops.put(STRREP, 1 + STR_PREC);
+ /* Expression operators. */
ops.put(LET, 0 + EXPR_PREC);
+
ops.put(BIND, 1 + EXPR_PREC);
}
@@ -136,16 +116,20 @@ public class Shunter {
* @return Whether or not the shunt succeeded.
*/
public boolean shuntTokens(final IList<Token> tks, final IList<Token> returned) {
- final Deque<Token> opStack = new LinkedList<>();
+ /* Operator stack for normal and unary operators. */
+ final Deque<Token> opStack = new LinkedList<>();
final Deque<Token> unaryOps = new LinkedList<>();
+ /* Currently returned lists. */
final Deque<Token> currReturned = new LinkedList<>();
+ /* Tokens to feed ahead of the current one. */
final Deque<Token> feed = new LinkedList<>();
for (final Token tk : tks.toIterable()) {
boolean succ;
+ /* Drain the feed queue. */
while (feed.size() != 0) {
succ = shuntToken(feed.poll(), opStack, unaryOps, currReturned, feed);
@@ -161,11 +145,12 @@ public class Shunter {
}
}
- // Flush leftover operators
+ /* Flush leftover operators. */
while (!opStack.isEmpty()) {
currReturned.addLast(opStack.pop());
}
+ /* Add the tokens to the returned list. */
for (final Token tk : currReturned) {
returned.add(tk);
}
@@ -173,9 +158,11 @@ public class Shunter {
return true;
}
+ /* Shunt a token. */
private boolean shuntToken(final Token tk, final Deque<Token> opStack,
final Deque<Token> unaryStack,
final Deque<Token> currReturned, final Deque<Token> feed) {
+ /* Handle unary operators. */
if (unaryStack.size() != 0) {
if (isUnary(tk)) {
unaryStack.add(tk);
@@ -187,6 +174,10 @@ public class Shunter {
final Token.Type unaryType = unaryOp.type;
if (unaryAdjectives.contains(unaryType)) {
+ /*
+ * Handle unary adjectives that take a
+ * non-operator.
+ */
if (isOp(tk)) {
Errors.inst.printError(EK_SHUNT_NOTADV, unaryOp.toString(), tk.toString());
return false;
@@ -205,6 +196,7 @@ public class Shunter {
return true;
} else if (unaryAdverbs.contains(unaryType)) {
+ /* Handle unary adverbs that take an operator. */
if (!isOp(tk)) {
Errors.inst.printError(EK_SHUNT_NOTADJ, unaryOp.toString(), tk.toString());
return false;
@@ -229,6 +221,7 @@ public class Shunter {
unaryStack.add(tk);
return true;
} else if (isOp(tk)) {
+ /* Drain higher precedence operators. */
while (!opStack.isEmpty() && isHigherPrec(tk, opStack.peek())) {
final Token newOp = opStack.pop();
@@ -247,17 +240,16 @@ public class Shunter {
currReturned.addLast(tk);
}
} else if (tk.type == CPAREN || tk.type == CBRACE) {
+ /* Handle closing delimiter. */
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:
Errors.inst.printError(EK_SHUNT_NOGROUP);
return false;
@@ -278,6 +270,7 @@ public class Shunter {
opStack.pop();
} else if (tk.type == GROUPSEP) {
+ /* Add a grouped token. */
final IList<Token> group = new FunctionalList<>();
while (currReturned.size() != 0 && !currReturned.peek().isGrouper()) {
@@ -301,8 +294,9 @@ public class Shunter {
return true;
}
+ /* Check if an operator has higher precedence. */
private boolean isHigherPrec(final Token lft, final Token rght) {
- final Token.Type left = lft.type;
+ final Token.Type left = lft.type;
final Token.Type right = rght.type;
boolean exists = ops.containsKey(right);
@@ -311,7 +305,7 @@ public class Shunter {
exists = true;
}
- // If it doesn't, the left is higher precedence.
+ /* If it doesn't, the left is higher precedence. */
if (!exists) {
return false;
}
@@ -338,6 +332,7 @@ public class Shunter {
return rightPrecedence >= leftPrecedence;
}
+ /* Check if something is an operator. */
private boolean isOp(final Token tk) {
final Token.Type ty = tk.type;
@@ -364,6 +359,7 @@ public class Shunter {
return false;
}
+ /* Check if something is a unary operator. */
private boolean isUnary(final Token tk) {
final Token.Type ty = tk.type;
diff --git a/dice-lang/src/bjc/dicelang/Token.java b/dice-lang/src/bjc/dicelang/Token.java
index 692430e..2841973 100644
--- a/dice-lang/src/bjc/dicelang/Token.java
+++ b/dice-lang/src/bjc/dicelang/Token.java
@@ -3,6 +3,10 @@ package bjc.dicelang;
import bjc.dicelang.dice.DieExpression;
import bjc.utils.funcdata.IList;
+/*
+ * @TODO 10/09/17 Ben Culkin :TokenReorg
+ * Split the class into subclasses based off of type.
+ */
/**
* Lexer token.
*/
diff --git a/dice-lang/src/bjc/dicelang/Tokenizer.java b/dice-lang/src/bjc/dicelang/Tokenizer.java
index 4bf0d5d..3e4a490 100644
--- a/dice-lang/src/bjc/dicelang/Tokenizer.java
+++ b/dice-lang/src/bjc/dicelang/Tokenizer.java
@@ -14,9 +14,11 @@ import bjc.utils.funcdata.IMap;
import bjc.utils.funcutils.StringUtils;
import bjc.utils.parserutils.TokenUtils;
-@SuppressWarnings("javadoc")
+/**
+ * Converts strings into tokens.
+ */
public class Tokenizer {
- // Literal tokens for tokenization
+ /* Literal tokens for tokenization */
private final IMap<String, Token.Type> litTokens;
private final DiceLangEngine eng;
@@ -65,7 +67,6 @@ public class Tokenizer {
case '}':
tk = tokenizeGrouping(token);
break;
-
default:
tk = tokenizeLiteral(token, stringLts);
}
@@ -78,6 +79,7 @@ public class Tokenizer {
Token tk = Token.NIL_TOKEN;
if (StringUtils.containsOnly(token, "\\" + token.charAt(0))) {
+ /* Handle multiple-grouped delimiters. */
switch (token.charAt(0)) {
case '(':
tk = new Token(OPAREN, token.length());
@@ -112,6 +114,7 @@ public class Tokenizer {
return tk;
}
+ /* Patterns for matching. */
private final Pattern hexadecimalMatcher =
Pattern.compile("\\A[\\-\\+]?0x[0-9A-Fa-f]+\\Z");
private final Pattern flexadecimalMatcher =
@@ -119,6 +122,7 @@ public class Tokenizer {
private final Pattern stringLitMatcher =
Pattern.compile("\\AstringLiteral(\\d+)\\Z");
+ /* Tokenize a literal value. */
private Token tokenizeLiteral(final String rtoken, final IMap<String, String> stringLts) {
Token tk = Token.NIL_TOKEN;
diff --git a/dice-lang/src/bjc/dicelang/dice/DiceBox.java b/dice-lang/src/bjc/dicelang/dice/DiceBox.java
index f7bf719..8d00d96 100644
--- a/dice-lang/src/bjc/dicelang/dice/DiceBox.java
+++ b/dice-lang/src/bjc/dicelang/dice/DiceBox.java
@@ -27,8 +27,11 @@ public class DiceBox {
/*
* @TODO 10/08/17 Ben Culkin :DieErrors :ErrorRefactor
* Use different types of exceptions to provide
- * better error messages. */
- System.out.println("ERROR: Could not parse die expression (Cause: %s)\n", ex.getMessage);
+ * better error messages.
+ */
+ String exMessage = ex.getMessage();
+
+ System.out.printf("ERROR: Could not parse die expression (Cause: %s)\n", exMessage);
ex.printStackTrace();
return null;
@@ -260,6 +263,10 @@ public class DiceBox {
* @return Whether or not the string is a valid command.
*/
public static boolean isValidExpression(final String exp) {
+ /* @NOTE
+ * Should this matcher/matches expression be abstracted in
+ * some way?
+ */
if (scalarDiePattern.matcher(exp).matches()) {
return true;
} else if (simpleDiePattern.matcher(exp).matches()) {
@@ -281,24 +288,23 @@ public class DiceBox {
}
}
- /*
- * Derive a predicate from a compare point
- */
+ /* Derive a predicate from a compare point */
private static Predicate<Long> deriveCond(final String patt) {
final long num = Long.parseLong(patt.substring(1));
+ /* @NOTE
+ * Should this be extended in some way, to provide other
+ * operators?
+ */
switch (patt.charAt(0)) {
case '<':
- return (roll) -> roll < num;
-
+ return (roll) -> (roll < num);
case '=':
- return (roll) -> roll == num;
-
+ return (roll) -> (roll == num);
case '>':
- return (roll) -> roll > num;
-
+ return (roll) -> (roll > num);
default:
- return (roll) -> false;
+ return (roll) -> (false);
}
}
}
diff --git a/dice-lang/src/bjc/dicelang/dice/DieExpression.java b/dice-lang/src/bjc/dicelang/dice/DieExpression.java
index 71b7a68..b8faeda 100644
--- a/dice-lang/src/bjc/dicelang/dice/DieExpression.java
+++ b/dice-lang/src/bjc/dicelang/dice/DieExpression.java
@@ -2,24 +2,25 @@ package bjc.dicelang.dice;
import java.util.Arrays;
+/*
+ * @NOTE
+ * I'm not a particularly large fan of sticking everything on this class
+ * and just documenting which fields are tied together in a non-obvious
+ * way. I think a class hierarchy might be better, but I am unsure of the
+ * details.
+ */
/**
* Represents either a die or a die list.
*
* @author Ben Culkin
*/
public class DieExpression {
- /**
- * Is this expression a list?
- */
+ /** Is this expression a list? */
public final boolean isList;
- /**
- * The scalar value in this expression, if there is one.
- */
+ /** The scalar value in this expression, if there is one. */
public Die scalar;
- /**
- * The list value in this expression, if there is one.
- */
+ /** The list value in this expression, if there is one. */
public DieList list;
/**
diff --git a/dice-lang/src/bjc/dicelang/dice/ExplodingDice.java b/dice-lang/src/bjc/dicelang/dice/ExplodingDice.java
index 6458f04..e891a1c 100644
--- a/dice-lang/src/bjc/dicelang/dice/ExplodingDice.java
+++ b/dice-lang/src/bjc/dicelang/dice/ExplodingDice.java
@@ -13,16 +13,13 @@ import java.util.function.Predicate;
* @author Ben Culkin
*/
public class ExplodingDice implements DieList {
- /*
- * The source die to use.
- */
+ /* The source die to use. */
private final Die source;
- /*
- * The conditions for exploding.
- */
+ /* The conditions for exploding. */
private final Predicate<Long> explodeOn;
private final String explodePattern;
+ /* Whether or not to apply a -1 penalty to explosions. */
private final boolean explodePenetrates;
/**
@@ -90,6 +87,7 @@ public class ExplodingDice implements DieList {
long oldRes = res;
final List<Long> resList = new LinkedList<>();
+ resList.add(res);
while (explodeOn.test(oldRes)) {
oldRes = source.rollSingle();
@@ -101,25 +99,26 @@ public class ExplodingDice implements DieList {
resList.add(oldRes);
}
- final long[] newRes = new long[resList.size() + 1];
- newRes[0] = res;
+ final long resArr[] = new long[resList.size()];
- int i = 1;
-
- for (final long rll : resList) {
- newRes[i] = rll;
- i += 1;
+ int i = 0;
+ for(long rll : resList) {
+ resArr[i] = rll;
+ i += 1;
}
- return newRes;
+ return resArr;
}
@Override
public String toString() {
+ String penString = explodePenetrates ? "p" : "";
+ String sourceString = source.toString();
+
if (explodePattern == null) {
- return source + (explodePenetrates ? "p" : "") + "!";
+ return String.format("%s%s!<complex-pred>", sourceString, penString);
}
- return source + (explodePenetrates ? "p" : "") + "!" + explodePattern;
+ return String.format("%s%s!%s", sourceString, penString, explodePattern);
}
}
diff --git a/dice-lang/src/bjc/dicelang/dice/FudgeDie.java b/dice-lang/src/bjc/dicelang/dice/FudgeDie.java
index 9457b58..23951b2 100644
--- a/dice-lang/src/bjc/dicelang/dice/FudgeDie.java
+++ b/dice-lang/src/bjc/dicelang/dice/FudgeDie.java
@@ -7,6 +7,7 @@ package bjc.dicelang.dice;
*
*/
public class FudgeDie implements Die {
+ /* The number of dice to roll. */
private final Die numDice;
/**
@@ -59,6 +60,8 @@ public class FudgeDie implements Die {
@Override
public String toString() {
- return numDice + "dF";
+ String dieString = numDice.toString();
+
+ return String.format("%sdF", dieString);
}
}
diff --git a/dice-lang/src/bjc/dicelang/dice/MathDie.java b/dice-lang/src/bjc/dicelang/dice/MathDie.java
index 1984581..e4f2953 100644
--- a/dice-lang/src/bjc/dicelang/dice/MathDie.java
+++ b/dice-lang/src/bjc/dicelang/dice/MathDie.java
@@ -7,6 +7,12 @@ package bjc.dicelang.dice;
*
*/
public class MathDie implements Die {
+ /*
+ * @TODO 10/08/17 Ben Culkin :MathGeneralize
+ * Why do we have the operator types hardcoded, instead of just
+ * having a general thing for applying a binary operator to dice?
+ * Fix this by changing it to the more general form.
+ */
/**
* The types of a math operator.
*
@@ -14,17 +20,11 @@ public class MathDie implements Die {
*
*/
public static enum MathOp {
- /**
- * Add two dice.
- */
+ /** Add two dice. */
ADD,
- /**
- * Subtract two dice.
- */
+ /** Subtract two dice. */
SUBTRACT,
- /**
- * Multiply two dice.
- */
+ /** Multiply two dice. */
MULTIPLY;
@Override
@@ -118,4 +118,4 @@ public class MathDie implements Die {
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
index e7b5afa..cbe9d3f 100644
--- a/dice-lang/src/bjc/dicelang/dice/ScalarDie.java
+++ b/dice-lang/src/bjc/dicelang/dice/ScalarDie.java
@@ -7,6 +7,7 @@ package bjc.dicelang.dice;
*
*/
public class ScalarDie implements Die {
+ /* The die value. */
private final long val;
/**
@@ -41,6 +42,6 @@ public class ScalarDie implements Die {
@Override
public String toString() {
- return Long.toString(val);
+ return String.format("%d", 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
index ee10070..6cae423 100644
--- a/dice-lang/src/bjc/dicelang/dice/SimpleDie.java
+++ b/dice-lang/src/bjc/dicelang/dice/SimpleDie.java
@@ -7,7 +7,17 @@ package bjc.dicelang.dice;
*
*/
public class SimpleDie implements Die {
+ /* The number of dice to roll. */
private final Die numDice;
+ /*
+ * The size of each dice to roll.
+ *
+ * Rolled once per role, not once for each dice rolled.
+ *
+ * @NOTE
+ * Would having some way to roll it once for each dice rolled be
+ * useful in any sort of case?
+ */
private final Die diceSize;
/**
@@ -106,4 +116,4 @@ public class SimpleDie implements Die {
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
index 4546238..8391054 100644
--- a/dice-lang/src/bjc/dicelang/dice/SimpleDieList.java
+++ b/dice-lang/src/bjc/dicelang/dice/SimpleDieList.java
@@ -5,9 +5,19 @@ package bjc.dicelang.dice;
*
* @author EVE
*
+ * @TODO 10/08/17 Ben Culkin :DieListGeneralize
+ * DieList in general should be changed to be able to be
+ * constructed from an arbitrary die using rollSingle and things
+ * like that.
*/
public class SimpleDieList implements DieList {
+ /* The number of dice to roll. */
private final Die numDice;
+ /*
+ * The size of each die to roll.
+ *
+ * Checked once per roll, not once per dice rolled.
+ */
private final Die size;
/**
@@ -64,4 +74,4 @@ public class SimpleDieList implements DieList {
public String toString() {
return numDice.toString() + "dl" + size.toString();
}
-} \ No newline at end of file
+}
diff --git a/dice-lang/src/bjc/dicelang/expr/Ezpr.java b/dice-lang/src/bjc/dicelang/expr/Ezpr.java
index 7186d6f..862c097 100644
--- a/dice-lang/src/bjc/dicelang/expr/Ezpr.java
+++ b/dice-lang/src/bjc/dicelang/expr/Ezpr.java
@@ -1,3 +1,7 @@
+/*
+ * @TODO 10/08/17 Ben Culkin :EzprFixing
+ * Implement these, and make sure they work correctly.
+ */
// package bjc.dicelang.expr;
// import bjc.utils.data.ITree;
diff --git a/dice-lang/src/bjc/dicelang/expr/Lexer.java b/dice-lang/src/bjc/dicelang/expr/Lexer.java
index bac866b..dfa0f76 100644
--- a/dice-lang/src/bjc/dicelang/expr/Lexer.java
+++ b/dice-lang/src/bjc/dicelang/expr/Lexer.java
@@ -6,20 +6,22 @@ import java.util.List;
import bjc.utils.funcdata.IList;
import bjc.utils.parserutils.splitter.ConfigurableTokenSplitter;
+/*
+ * @TODO 10/08/18 :IntExpressions
+ * Add support for integer constants, and maybe floating-point ones as well
+ * if you feel like. Heck, you could even go for ratio constants and things
+ * as well.
+ */
/**
* Implements the lexer for simple expression operations.
*
* @author Ben Culkin
*/
public class Lexer {
- /*
- * Splitter we use.
- */
+ /* Splitter we use. */
private final ConfigurableTokenSplitter split;
- /**
- * Create a new expression lexer.
- */
+ /** Create a new expression lexer. */
public Lexer() {
split = new ConfigurableTokenSplitter(true);
@@ -39,14 +41,19 @@ public class Lexer {
* @return A series of infix tokens representing the command.
*/
public Token[] lexString(final String inp, final Tokens tks) {
+ /* Split tokens on whitespace. */
final String[] spacedTokens = inp.split("[ \t]");
+ /* Tokens to return. */
+ final List<Token> tokens = new LinkedList<>();
- final List<Token> tokens = new LinkedList<>();
-
+ /* Process each token. */
for (final String spacedToken : spacedTokens) {
+ /* Split on operators. */
final IList<String> splitTokens = split.split(spacedToken);
- final IList<Token> rawTokens = splitTokens.map(tok -> tks.lexToken(tok, spacedToken));
+ /* Convert strings to tokens. */
+ final IList<Token> rawTokens = splitTokens.map(tok -> tks.lexToken(tok, spacedToken));
+ /* Add tokens to results. */
rawTokens.forEach(tokens::add);
}
diff --git a/dice-lang/src/bjc/dicelang/expr/Parser.java b/dice-lang/src/bjc/dicelang/expr/Parser.java
index 6d34b96..5fa2d3d 100644
--- a/dice-lang/src/bjc/dicelang/expr/Parser.java
+++ b/dice-lang/src/bjc/dicelang/expr/Parser.java
@@ -13,6 +13,10 @@ import bjc.utils.parserutils.TreeConstructor;
* @author Ben Culkin
*/
public class Parser {
+ /*
+ * @TODO 10/08/17 Ben Culkin :MainSeperation
+ * This main method should be moved to its own class.
+ */
/**
* Main method.
*
@@ -20,100 +24,81 @@ public class Parser {
* Unused CLI args.
*/
public static void main(final String[] args) {
- /*
- * Create our objects.
- */
+ /* Create our objects. */
final Tokens toks = new Tokens();
final Lexer lex = new Lexer();
- /*
- * Prepare our input.
- */
+ /* Prepare our input source. */
final Scanner scan = new Scanner(System.in);
- /*
- * Read initial command.
- */
+ /* Read initial command. */
System.out.print("Enter a math expression (blank line to quit): ");
String ln = scan.nextLine().trim();
- /*
- * Enter REPL loop.
- */
+ /* Enter REPL loop. */
while (!ln.equals("")) {
- /*
- * Print raw command.
- */
+ /* Print raw command. */
System.out.println("Raw command: " + ln);
System.out.println();
- /*
- * Lex command to infix tokens.
- */
+ /* Lex command to infix tokens. */
final Token[] infixTokens = lex.lexString(ln, toks);
System.out.println("Lexed tokens: ");
-
for (final Token tok : infixTokens) {
System.out.println("\t" + tok);
}
- /*
- * Print out infix expression.
- */
+ /* Print out infix expression. */
System.out.print("Lexed expression: ");
-
for (final Token tok : infixTokens) {
System.out.print(tok.toExpr() + " ");
}
+ /* Space stages. */
System.out.println();
System.out.println();
- /*
- * Shunt infix tokens to postfix tokens.
- */
+ /* Shunt infix tokens to postfix tokens. */
final Token[] postfixTokens = Shunter.shuntTokens(infixTokens);
System.out.println("Lexed tokens: ");
-
for (final Token tok : postfixTokens) {
System.out.println("\t" + tok);
}
- /*
- * Print out postfix tokens.
- */
+ /* Print out postfix tokens. */
System.out.print("Shunted expression: ");
-
for (final Token tok : postfixTokens) {
System.out.print(tok.toExpr() + " ");
}
+ /* Space stages. */
System.out.println();
System.out.println();
- final FunctionalList<Token> tokList = new FunctionalList<>(Arrays.asList(postfixTokens));
+ /* Construct a list from the array of tokens. */
+ final FunctionalList<Token> tokList = new FunctionalList<>(
+ Arrays.asList(postfixTokens));
+
+ /* Construct a tree from the list of postfixed tokens. */
final ITree<Token> ast = TreeConstructor.constructTree(tokList,
- tok -> tok.typ.isOperator);
+ tok -> tok.typ.isOperator);
- /*
- * Print the tree, then the canonical expression for it.
- */
+ /* Print the tree, then the canonical expression for it. */
System.out.println("Parsed tree");
System.out.println(ast.toString());
System.out.println("\nCanonical expr: " + toCanonicalExpr(ast));
+ /* Space stages. */
+ System.out.println();
System.out.println();
- /*
- * Prompt for a new expression.
- */
+ /* Prompt for a new expression. */
System.out.print("Enter a math expression (blank line to quit): ");
+ /* Read it. */
ln = scan.nextLine().trim();
}
- /*
- * Cleanup after ourselves.
- */
+ /* Cleanup after ourselves. */
scan.close();
}
@@ -124,38 +109,39 @@ public class Parser {
private static String toCanonicalExpr(final ITree<Token> ast) {
final Token data = ast.getHead();
- if (ast.getChildrenCount() == 0)
- /*
- * Handle leaf nodes.
- */
- {
+ if (ast.getChildrenCount() == 0) {
+ /* Handle leaf nodes. */
return data.toExpr();
}
- final ITree<Token> left = ast.getChild(0);
+ /* The left/right children. */
+ final ITree<Token> left = ast.getChild(0);
final ITree<Token> right = ast.getChild(1);
- String leftExpr = toCanonicalExpr(left);
+ /* Recursively canonicalize them. */
+ String leftExpr = toCanonicalExpr(left);
String rightExpr = toCanonicalExpr(right);
- /*
- * Add parens if the left was higher priority.
- */
+ /* Add parens if the left was higher priority. */
if (left.getChildrenCount() == 0) {
- if (left.getHead().typ.operatorPriority >= data.typ.operatorPriority) {
- leftExpr = "(" + leftExpr + ")";
+ int leftPriority = left.getHead().typ.operatorPriority;
+ int dataPriority = data.typ.operatorPriority;
+
+ if (leftPriority >= dataPriority) {
+ leftExpr = String.format("(%s)", leftExpr);
}
}
- /*
- * Add parens if the right was higher priority.
- */
+ /* Add parens if the right was higher priority. */
if (right.getChildrenCount() == 0) {
- if (right.getHead().typ.operatorPriority >= data.typ.operatorPriority) {
- rightExpr = "(" + rightExpr + ")";
+ int rightPriority = right.getHead().typ.operatorPriority;
+ int dataPriority = data.typ.operatorPriority;
+
+ if (rightPriority >= dataPriority) {
+ rightExpr = String.format("(%s)", rightExpr);
}
}
- return leftExpr + " " + data.toExpr() + " " + rightExpr;
+ return String.format("%s %s %s", leftExpr, data.toExpr(), rightExpr);
}
-} \ No newline at end of file
+}
diff --git a/dice-lang/src/bjc/dicelang/expr/Shunter.java b/dice-lang/src/bjc/dicelang/expr/Shunter.java
index 3e49356..213e473 100644
--- a/dice-lang/src/bjc/dicelang/expr/Shunter.java
+++ b/dice-lang/src/bjc/dicelang/expr/Shunter.java
@@ -11,6 +11,11 @@ import java.util.List;
* @author Ben Culkin
*/
public class Shunter {
+ /*
+ * @NOTE
+ * Why does this method return an array, and not the list of
+ * tokens?
+ */
/**
* Convert a infix series of tokens to a postfix series of tokens.
*
@@ -20,26 +25,27 @@ public class Shunter {
* @return The tokens in postfix order.
*/
public static Token[] shuntTokens(final Token[] infixTokens) {
+ /* The returned tokens. */
final List<Token> postfixTokens = new ArrayList<>(infixTokens.length);
+ /* The current stack of operators. */
final Deque<Token> opStack = new LinkedList<>();
- /*
- * Shunt each token.
- */
+ /* Shunt each token. */
for (final Token tok : infixTokens) {
- /*
- * Handle operators.
- */
+ /* Handle operators. */
if (tok.typ.isOperator) {
Token curOp = opStack.peek();
/*
* Check if an operator is higher priority,
* respecting their left associativity.
+ *
+ * @NOTE
+ * Should this be factored out into a
+ * method?
*/
int leftPriority = tok.typ.operatorPriority;
-
int rightPriority;
if (curOp == null) {
@@ -56,11 +62,9 @@ public class Shunter {
*/
while (!opStack.isEmpty() && isHigherPrec) {
postfixTokens.add(opStack.pop());
-
curOp = opStack.peek();
leftPriority = tok.typ.operatorPriority;
-
if (curOp == null) {
rightPriority = 0;
} else {
@@ -82,9 +86,7 @@ public class Shunter {
*/
while (curOp.typ != TokenType.OPAREN) {
final Token tk = opStack.pop();
-
postfixTokens.add(tk);
-
curOp = opStack.peek();
}
@@ -105,4 +107,4 @@ public class Shunter {
return postfixTokens.toArray(new Token[0]);
}
-} \ No newline at end of file
+}
diff --git a/dice-lang/src/bjc/dicelang/expr/Token.java b/dice-lang/src/bjc/dicelang/expr/Token.java
index 1a506bf..bf92f97 100644
--- a/dice-lang/src/bjc/dicelang/expr/Token.java
+++ b/dice-lang/src/bjc/dicelang/expr/Token.java
@@ -1,14 +1,18 @@
package bjc.dicelang.expr;
+/*
+ * @TODO 10/08/17 :TokenReorg
+ * I am not a fan of this 'having a bunch of subclasses' in one thing I
+ * seem to have been doing around this project. This should be multiple
+ * subclasses, one for each value for TokenType.
+ */
/**
* Represents a lexical token.
*
* @author Ben Culkin
*/
public class Token {
- /*
- * The state for this token.
- */
+ /* The state for this token. */
private final Tokens tks;
/**
@@ -18,14 +22,10 @@ public class Token {
*/
public final TokenType typ;
- /**
- * The integer value attached to this token.
- */
+ /** The integer value attached to this token. */
public int intValue;
- /**
- * The original string this token was part of.
- */
+ /** The original string this token was part of. */
public String rawValue;
/**
@@ -44,21 +44,20 @@ public class Token {
this.typ = type;
rawValue = raw;
-
tks = toks;
}
@Override
public String toString() {
String typeStr = typ.toString();
- typeStr += " (" + typ.name() + ")";
+ typeStr = String.format("%s (%s)", typeStr, typ.name());
if (typ == TokenType.VREF) {
typeStr += " (ind. " + intValue;
typeStr += ", sym. \"" + tks.symbolTable.get(intValue) + "\")";
}
- return typeStr + " (originally from: " + rawValue + ")";
+ return String.format("%s (originally from: %s)", typeStr, rawValue);
}
/**
@@ -70,27 +69,20 @@ 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 "???";
}
}
-} \ No newline at end of file
+}
diff --git a/dice-lang/src/bjc/dicelang/expr/TokenType.java b/dice-lang/src/bjc/dicelang/expr/TokenType.java
index d88283e..ad01917 100644
--- a/dice-lang/src/bjc/dicelang/expr/TokenType.java
+++ b/dice-lang/src/bjc/dicelang/expr/TokenType.java
@@ -2,59 +2,46 @@ package bjc.dicelang.expr;
/**
* Represents the type of this token.
+ *
+ * @author Ben Culkin
*/
public enum TokenType {
- /**
- * Represents +
+ /*
+ * @NOTE
+ * Do we want to switch to auto-numbering the tokens? They were
+ * manually numbered because this was an assignment for PoPL and
+ * that was what Dr. Naz wanted.
*/
- ADD(14, true, 0),
- /**
- * Represents -
- */
- SUBTRACT(15, true, 0),
- /**
- * Represents *
- */
+ /** Represents + */
+ ADD( 14, true, 0),
+ /** Represents - */
+ SUBTRACT(15, true, 0),
+ /** Represents * */
MULTIPLY(16, true, 1),
- /**
- * Represents /
- */
- DIVIDE(17, true, 1),
+ /** Represents / */
+ DIVIDE( 17, true, 1),
- /**
- * Represents variable names.
- */
+ /** Represents variable names. */
VREF(11),
- /**
- * Represents (
- */
+ /** Represents ( */
OPAREN(0, false, 100),
- /**
- * Represents )
- */
+ /** Represents ) */
CPAREN(0, false, 100);
- /**
- * The ID number for this token type.
- */
+ /** The ID number for this token type. */
public final int nVal;
- /**
- * Whether or not this type of token is an operator.
- */
+ /** Whether or not this type of token is an operator. */
public final boolean isOperator;
- /**
- * The priority of this operator, if it is one.
- */
+ /** The priority of this operator, if it is one. */
public final int operatorPriority;
+ /* Create a new token. */
private TokenType(final int num, final boolean isOp, final int priority) {
- nVal = num;
-
- isOperator = isOp;
-
+ nVal = num;
+ isOperator = isOp;
operatorPriority = priority;
}
@@ -66,4 +53,4 @@ public enum TokenType {
public String toString() {
return Integer.toString(nVal);
}
-} \ No newline at end of file
+}
diff --git a/dice-lang/src/bjc/dicelang/expr/Tokens.java b/dice-lang/src/bjc/dicelang/expr/Tokens.java
index f763d37..287d2b4 100644
--- a/dice-lang/src/bjc/dicelang/expr/Tokens.java
+++ b/dice-lang/src/bjc/dicelang/expr/Tokens.java
@@ -11,43 +11,39 @@ import java.util.Map;
*
*/
public class Tokens {
- /*
- * Contains mappings from variable references to string names.
- */
+ /* Contains mappings from variable references to string names. */
private final Map<Integer, String> symTab;
- /*
- * Reverse index into the symbol table.
- */
+ /* Reverse index into the symbol table. */
private final Map<String, Integer> revSymTab;
- /**
- * Read-only view on the symbol table.
- */
+ /** Read-only view on the symbol table. */
public final Map<Integer, String> symbolTable;
- /*
- * Next index into the symbol table.
- */
+ /* Next index into the symbol table. */
private int nextSym;
- /*
- * Mapping from literal tokens to token types.
- */
+ /* Mapping from literal tokens to token types. */
private final Map<String, TokenType> litTokens;
- /**
- * Create a new set of tokens.
- */
+ /** Create a new set of tokens. */
public Tokens() {
+ /* Create tables. */
symTab = new HashMap<>();
revSymTab = new HashMap<>();
+ /* Init public view. */
symbolTable = Collections.unmodifiableMap(symTab);
+ /* Set sym ID. */
nextSym = 0;
+ /*
+ * Setup literal mappings.
+ *
+ * @NOTE
+ * Should this be a static member?
+ */
litTokens = new HashMap<>();
-
litTokens.put("+", TokenType.ADD);
litTokens.put("-", TokenType.SUBTRACT);
litTokens.put("*", TokenType.MULTIPLY);
@@ -68,32 +64,30 @@ public class Tokens {
*/
public Token lexToken(final String tok, final String raw) {
if (litTokens.containsKey(tok)) {
+ /* Return matching literal token. */
return new Token(litTokens.get(tok), raw, this);
}
+ /* Its a variable reference. */
return parseVRef(tok, raw);
}
- /*
- * Parse a variable reference.
- */
+ /* Parse a variable reference. */
private Token parseVRef(final String tok, final String raw) {
final Token tk = new Token(TokenType.VREF, raw, this);
if (revSymTab.containsKey(tok)) {
- /*
- * Reuse the entry if it exists.
- */
+ /* Reuse the entry if it exists. */
tk.intValue = revSymTab.get(tok);
} else {
- /*
- * Create a new entry.
- */
+ /* Create a new entry. */
tk.intValue = nextSym;
+ /* Record it. */
symTab.put(nextSym, tok);
revSymTab.put(tok, nextSym);
+ /* Next ID. */
nextSym += 1;
}
diff --git a/dice-lang/src/bjc/dicelang/scl/StreamControlConsole.java b/dice-lang/src/bjc/dicelang/scl/StreamControlConsole.java
index 8ace8ad..649c6fa 100644
--- a/dice-lang/src/bjc/dicelang/scl/StreamControlConsole.java
+++ b/dice-lang/src/bjc/dicelang/scl/StreamControlConsole.java
@@ -8,21 +8,43 @@ import java.util.Scanner;
import java.util.function.Supplier;
+/**
+ * Implement a SCL REPL
+ *
+ * @author Ben Culkin
+ */
public class StreamControlConsole {
+ /*
+ * @TODO 10/08/17 :SCLArgs
+ * Do something useful with the CLI args.
+ *
+ */
+ /**
+ * Main method
+ *
+ * @param args
+ * Unused CLI args.
+ */
public static void main(String[] args) {
- /* Initialize vars. */
- /* We're not using the DiceLangEngine in the streams yet. */
- StreamEngine sengine = new StreamEngine(null);
+ /*
+ * Initialize vars.
+ *
+ * We can get away with passing the null, because StreamEngine
+ * doesn't reference any parts of DiceLangEngine.
+ */
+ StreamEngine sengine = new StreamEngine(null);
StreamControlEngine sclengine = new StreamControlEngine(sengine);
- Scanner scn = new Scanner(System.in);
+ Scanner scn = new Scanner(System.in);
/* Get input from the user. */
System.out.print("Enter a SCL command string (blank to exit): ");
+ /* Process it. */
while (scn.hasNextLine()) {
- String ln = scn.nextLine();
+ String ln = scn.nextLine().trim();
- if (ln.trim().equals("")) {
+ if (ln.equals("")) {
+ /* Ignore empty lines. */
break;
}
@@ -32,16 +54,16 @@ public class StreamControlConsole {
/* Run the stream engine on the tokens. */
boolean succ = sengine.doStreams(tokens, res);
-
if (!succ) {
+ System.out.printf("ERROR: Stream engine failed for line '%s'\n", ln);
continue;
}
/* Run the command through SCL. */
tokens = res.toArray(new String[res.getSize()]);
succ = sclengine.runProgram(tokens);
-
if (!succ) {
+ System.out.printf("ERROR: SCL engine failed for line '%s'\n", ln);
continue;
}
diff --git a/dice-lang/src/bjc/dicelang/scl/StreamControlEngine.java b/dice-lang/src/bjc/dicelang/scl/StreamControlEngine.java
index 2952a89..d5e8b72 100644
--- a/dice-lang/src/bjc/dicelang/scl/StreamControlEngine.java
+++ b/dice-lang/src/bjc/dicelang/scl/StreamControlEngine.java
@@ -1,37 +1,5 @@
package bjc.dicelang.scl;
-import static bjc.dicelang.Errors.ErrorKey.EK_SCL_INVARG;
-import static bjc.dicelang.Errors.ErrorKey.EK_SCL_INVTOKEN;
-import static bjc.dicelang.Errors.ErrorKey.EK_SCL_MMQUOTE;
-import static bjc.dicelang.Errors.ErrorKey.EK_SCL_SUNDERFLOW;
-import static bjc.dicelang.Errors.ErrorKey.EK_SCL_UNWORD;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.ARRAY;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.BLIT;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.DELETESTREAM;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.DQUOTE;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.DROP;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.FLIT;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.ILIT;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.LEFTSTREAM;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.MAKEARRAY;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.MAKEEXEC;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.MAKEUNEXEC;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.MERGESTREAM;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.NDROP;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.NEWSTREAM;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.NIP;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.NNIP;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.OBRACE;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.OBRACKET;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.RIGHTSTREAM;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.SLIT;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.SQUOTE;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.STACKCOUNT;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.STACKEMPTY;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.SYMBOL;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.WORD;
-import static bjc.dicelang.scl.StreamControlEngine.Token.Type.WORDS;
-
import java.util.HashMap;
import java.util.Map;
@@ -42,117 +10,118 @@ import bjc.utils.funcdata.FunctionalList;
import bjc.utils.funcdata.IList;
import bjc.utils.parserutils.TokenUtils;
+import static bjc.dicelang.Errors.ErrorKey.*;
+import static bjc.dicelang.scl.StreamControlEngine.Token.Type.*;
+
+/*
+ * @TODO 10/08/17 Ben Culkin :SCLReorg
+ * This is a large enough class that it should maybe be split into
+ * subclasses.
+ */
/**
* Runs a Stream Control Language (SCL) program.
*
* SCL is a stack-based concatenative language based mostly off of Postscript
* and Factor, with inspiration from various other languages.
+ *
+ * @author Ben Culkin
*/
public class StreamControlEngine {
- static class Token {
+ /*
+ * @TODO 10/08/17 Ben Culkin :TokenSplit
+ * Again with the multiple subclasses in one class. Split it so
+ * that each subclass only has the fields it needs.
+ */
+ public static class Token {
public static enum Type {
- /*
- * Natural tokens. These come directly from strings
- */
+ /* Natural tokens. These come directly from strings */
ILIT, FLIT, BLIT, SQUOTE, DQUOTE, OBRACKET, OBRACE, SYMBOL, WORD,
- /*
- * Synthetic tokens. These are produced from special
- * tokens.
- */
+ /* Synthetic tokens. These are produced from special tokens. */
SLIT, WORDS, ARRAY,
+ /* Word tokens These are subordinate to WORD tokens */
/*
- * Word tokens These are subordinate to WORD tokens
- */
- /*
- * Array manipulation
+ * @NOTE
+ * These should really be in their own enum.
*/
+ /* Array manipulation */
MAKEARRAY, MAKEEXEC, MAKEUNEXEC,
- /*
- * Stream manipulation
- */
+ /* Stream manipulation */
NEWSTREAM, LEFTSTREAM, RIGHTSTREAM, DELETESTREAM, MERGESTREAM,
- /*
- * Stack manipulation
- */
+ /* Stack manipulation */
STACKCOUNT, STACKEMPTY, DROP, NDROP, NIP, NNIP,
}
- /*
- * The type of this token
- */
+ /* The type of this token */
public Type type;
- /*
- * Used for ILIT
- */
+ /* Used for ILIT */
public long intVal;
- /*
- * Used for FLIT
- */
+ /* Used for FLIT */
public double floatVal;
- /*
- * Used for BLIT
- */
+ /* Used for BLIT */
public boolean boolVal;
- /*
- * Used for SYMBOL SLIT
- */
+ /* Used for SYMBOL & SLIT */
public String stringVal;
- /*
- * Used for WORD
- */
+ /* Used for WORD */
public Token tokenVal;
- /*
- * Used for WORDS ARRAY
- */
+ /* Used for WORDS & ARRAY */
public IList<Token> tokenVals;
+ /* Create a new token. */
public Token(final Type typ) {
type = typ;
}
+ /* Create a new token. */
public Token(final Type typ, final long iVal) {
this(typ);
intVal = iVal;
}
+ /* Create a new token. */
public Token(final Type typ, final double dVal) {
this(typ);
floatVal = dVal;
}
+ /* Create a new token. */
public Token(final Type typ, final boolean bVal) {
this(typ);
boolVal = bVal;
}
+ /* Create a new token. */
public Token(final Type typ, final String sVal) {
this(typ);
stringVal = sVal;
}
+ /* Create a new token. */
public Token(final Type typ, final Token tVal) {
this(typ);
tokenVal = tVal;
}
+ /* Create a new token. */
public Token(final Type typ, final Token.Type tVal) {
this(typ, new Token(tVal));
}
+ /* Create a new token. */
public Token(final Type typ, final IList<Token> tVals) {
this(typ);
tokenVals = tVals;
}
+ /* Convert a string into a token. */
public static Token tokenizeString(final String token) {
if (litTokens.containsKey(token)) {
return new Token(litTokens.get(token));
@@ -174,10 +143,13 @@ public class StreamControlEngine {
}
}
+ /* The literal tokens. */
private static final Map<String, Token.Type> litTokens;
+ /* The builtin words. */
private static final Map<String, Token.Type> builtinWords;
static {
+ /* Init literal tokens. */
litTokens = new HashMap<>();
litTokens.put("'", SQUOTE);
@@ -185,6 +157,7 @@ public class StreamControlEngine {
litTokens.put("[", OBRACKET);
litTokens.put("{", OBRACE);
+ /* Init builtin words. */
builtinWords = new HashMap<>();
builtinWords.put("makearray", MAKEARRAY);
@@ -204,11 +177,13 @@ public class StreamControlEngine {
}
}
+ /* The stream engine we're hooked to. */
private final StreamEngine eng;
+ /* The current stack state. */
private final Stack<Token> curStack;
- @SuppressWarnings("unused")
+ /* Map of user defined words. */
private final Map<String, Token> words;
/**
@@ -234,48 +209,49 @@ public class StreamControlEngine {
*/
public boolean runProgram(final String[] tokens) {
for (int i = 0; i < tokens.length; i++) {
+ /* Tokenize each token. */
final String token = tokens[i];
- final Token tok = Token.tokenizeString(token);
+ final Token tok = Token.tokenizeString(token);
if (tok == null) {
+ System.out.printf("ERROR: Tokenization failed for '%s'\n", token);
return false;
}
+ /* Handle token types. */
switch (tok.type) {
case SQUOTE:
+ /* Handle single-quotes. */
i = handleSingleQuote(i, tokens);
-
if (i == -1) {
return false;
}
-
break;
-
case OBRACKET:
+ /* Handle delimited brackets. */
i = handleDelim(i, tokens, "]");
-
if (i == -1) {
return false;
}
-
break;
-
case OBRACE:
+ /* Handle delimited braces. */
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);
+ /* Handle words. */
+ if(!handleWord(tok)) {
+ System.out.printf("WARNING: Execution of word '%s' failed\n", tok);
+ }
break;
-
default:
+ /* Put it onto the stack. */
curStack.push(tok);
break;
}
@@ -287,118 +263,90 @@ public class StreamControlEngine {
private boolean handleWord(final Token tk) {
boolean succ = true;
+ /* Handle each type of word. */
+ /*
+ * @NOTE
+ * This should probably use something other than a switch
+ * statement.
+ */
switch (tk.tokenVal.type) {
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());
return false;
}
-
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;
@@ -407,6 +355,7 @@ public class StreamControlEngine {
return true;
}
+ /* Handle nipping a specified number of items. */
private boolean handleNNip() {
final Token num = curStack.pop();
@@ -426,6 +375,7 @@ public class StreamControlEngine {
return true;
}
+ /* Handle dropping a specified number of items. */
private boolean handleNDrop() {
final Token num = curStack.pop();
@@ -445,6 +395,7 @@ public class StreamControlEngine {
return true;
}
+ /* Handle toggling the executable flag on an array. */
private boolean toggleExec(final boolean exec) {
final Token top = curStack.top();
@@ -467,6 +418,7 @@ public class StreamControlEngine {
return true;
}
+ /* Handle creating an array. */
private boolean makeArray() {
final Token num = curStack.pop();
@@ -485,6 +437,7 @@ public class StreamControlEngine {
return true;
}
+ /* Handle a delimited series of tokens. */
private int handleDelim(final int i, final String[] tokens, final String delim) {
final IList<Token> toks = new FunctionalList<>();
@@ -503,42 +456,31 @@ 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
- */
+ /* Move to the next token */
n += 1;
if (n >= tokens.length) {
@@ -549,16 +491,18 @@ public class StreamControlEngine {
tok = tokens[n];
}
- /*
- * Skip the closing bracket
- */
+ /* Skip the closing bracket */
n += 1;
+ /* @NOTE
+ * Instead of being hardcoded, this should be a parameter.
+ */
curStack.push(new Token(WORDS, toks));
return n;
}
+ /* Handle a single-quoted string. */
private int handleSingleQuote(final int i, final String[] tokens) {
final StringBuilder sb = new StringBuilder();
@@ -573,17 +517,13 @@ public class StreamControlEngine {
while (!tok.equals("'")) {
if (tok.matches("\\\\+'")) {
- /*
- * Handle escaped quotes.
- */
+ /* Handle escaped quotes. */
sb.append(tok.substring(1));
} else {
sb.append(tok);
}
- /*
- * Move to the next token
- */
+ /* Move to the next token */
n += 1;
if (n >= tokens.length) {
diff --git a/dice-lang/src/bjc/dicelang/scl/StreamEngine.java b/dice-lang/src/bjc/dicelang/scl/StreamEngine.java
index 2082c9b..6e970b7 100644
--- a/dice-lang/src/bjc/dicelang/scl/StreamEngine.java
+++ b/dice-lang/src/bjc/dicelang/scl/StreamEngine.java
@@ -103,15 +103,18 @@ public class StreamEngine {
for (final String tk : toks) {
/* Process stream commands. */
if (tk.startsWith("{@S") && !quoteMode) {
- if (tk.equals("{@SQ}")) {
+ if (tk.equals("{@SQ}")) {
+ /* Start quoting. */
quoteMode = true;
} else if (!processCommand(tk)) {
return false;
}
} else {
if (tk.equals("{@SU}")) {
+ /* Stop quoting. */
quoteMode = false;
} else if (tk.startsWith("\\") && tk.endsWith("{@SU}")) {
+ /* Unquote quoted end. */
currStream.add(tk.substring(1));
} else {
currStream.add(tk);
@@ -120,15 +123,14 @@ public class StreamEngine {
}
for (final String tk : currStream) {
+ /* Collect tokens from the current stream. */
dest.add(tk);
}
return true;
}
- /**
- * Create a new stream.
- */
+ /** Create a new stream. */
public void newStream() {
streams.insertAfter(new FunctionalList<>());
}
@@ -202,65 +204,57 @@ public class StreamEngine {
char[] comms = null;
if (tk.length() > 5) {
+ /* Pull off {@S and closing } */
comms = tk.substring(3, tk.length() - 1).toCharArray();
} else {
+ /* Its a single char. command. */
comms = new char[1];
comms[0] = tk.charAt(3);
}
boolean succ;
+ /* Process each command. */
+ /*
+ * @TODO 10/09/17 Ben Culkin :StreamCommands
+ * This should probably be refactored in some way, so as to
+ * make it easier to add new commands.
+ */
for (final char comm : comms) {
switch (comm) {
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;
diff --git a/dice-lang/src/bjc/dicelang/util/ResourceLoader.java b/dice-lang/src/bjc/dicelang/util/ResourceLoader.java
index 37cf5b3..db5c6fc 100644
--- a/dice-lang/src/bjc/dicelang/util/ResourceLoader.java
+++ b/dice-lang/src/bjc/dicelang/util/ResourceLoader.java
@@ -6,6 +6,7 @@ import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
+import java.nio.file.Path;
import java.nio.file.Paths;
import bjc.dicelang.Errors;
@@ -30,7 +31,9 @@ public class ResourceLoader {
final URL fle = ResourceLoader.class.getResource("/data/help/" + name + ".help");
try {
- return Files.lines(Paths.get(fle.toURI())).toArray(sze -> new String[sze]);
+ Path pth = Paths.get(fle.toURI());
+
+ return Files.lines(pth).toArray(sze -> new String[sze]);
} catch (IOException | URISyntaxException ioex) {
Errors.inst.printError(EK_MISC_IOEX, fle.toString());
}