summaryrefslogtreecommitdiff
path: root/dice-lang/src/bjc/dicelang/DiceLangConsole.java
diff options
context:
space:
mode:
Diffstat (limited to 'dice-lang/src/bjc/dicelang/DiceLangConsole.java')
-rw-r--r--dice-lang/src/bjc/dicelang/DiceLangConsole.java261
1 files changed, 261 insertions, 0 deletions
diff --git a/dice-lang/src/bjc/dicelang/DiceLangConsole.java b/dice-lang/src/bjc/dicelang/DiceLangConsole.java
new file mode 100644
index 0000000..d9d9288
--- /dev/null
+++ b/dice-lang/src/bjc/dicelang/DiceLangConsole.java
@@ -0,0 +1,261 @@
+package bjc.dicelang;
+
+import static bjc.dicelang.Errors.ErrorKey.*;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.LinkedList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import jline.ConsoleReader;
+import jline.Terminal;
+
+public class DiceLangConsole {
+ private int commandNumber;
+
+ private DiceLangEngine eng;
+
+ private ConsoleReader read;
+
+ public DiceLangConsole(String[] args) {
+ // @TODO do something with the args
+ commandNumber = 0;
+
+ eng = new DiceLangEngine();
+
+ Terminal.setupTerminal();
+ }
+
+ public void run() {
+ try {
+ read = new ConsoleReader();
+ } catch(IOException ioex) {
+ System.out.println("ERROR: Console init failed");
+ return;
+ }
+
+ System.out.println("dice-lang v0.2");
+
+ String comm = null;
+
+ try {
+ comm = read.readLine(String.format("(%d) dice-lang> ", commandNumber));
+ } catch (IOException ioex) {
+ System.out.println("ERROR: I/O failed");
+ return;
+ }
+
+ while(!comm.equals("quit") && !comm.equals("exit")) {
+ if(comm.startsWith("pragma")) {
+ boolean success = handlePragma(comm.substring(7));
+
+ if(success) System.out.println("Pragma completed succesfully");
+ else System.out.println("Pragma execution failed");
+ } else {
+ System.out.printf("\tRaw command: %s\n", comm);
+
+ boolean success = eng.runCommand(comm);
+
+ if(success) System.out.println("Command completed succesfully");
+ else System.out.println("Command execution failed");
+
+ commandNumber += 1;
+ }
+
+ try {
+ comm = read.readLine(String.format("(%d) dice-lang> ", commandNumber));
+ } catch (IOException ioex) {
+ System.out.println("ERROR: I/O failed");
+ return;
+ }
+ }
+ }
+
+ private boolean handlePragma(String pragma) {
+ System.out.println("\tRaw pragma: " + pragma);
+
+ String pragmaName = null;
+ int firstIndex = pragma.indexOf(' ');
+ if(firstIndex == -1) {
+ pragmaName = pragma;
+ } else {
+ pragmaName = pragma.substring(0, firstIndex);
+ }
+
+ switch(pragmaName) {
+ case "debug":
+ System.out.println("\tDebug mode is now " + eng.toggleDebug());
+ break;
+ case "postfix":
+ System.out.println("\tPostfix mode is now " + eng.togglePostfix());
+ break;
+ case "prefix":
+ System.out.println("\tPrefix mode is now " + eng.togglePrefix());
+ break;
+ case "stepeval":
+ System.out.println("\tStepeval mode is now" + eng.toggleStepEval());
+ break;
+ case "define":
+ return defineMode(pragma.substring(7));
+ case "help":
+ return helpMode(pragma.substring(5));
+ default:
+ Errors.inst.printError(EK_CONS_INVPRAG, pragma);
+ return false;
+ }
+
+ return true;
+ }
+
+ private boolean helpMode(String pragma) {
+ switch(pragma.trim()) {
+ case "help":
+ System.out.println("\tGet help on pragmas");
+ break;
+ case "debug":
+ System.out.println("\tToggle debug mode. (Output stage results)");
+ break;
+ case "postfix":
+ System.out.println("\tToggle postfix mode. (Don't shunt tokens)");
+ break;
+ case "prefix":
+ System.out.println("\tToggle prefix mode. (Reverse token order instead of shunting)");
+ break;
+ case "stepeval":
+ System.out.println("\tToggle stepeval mode. (Print out evaluation progress)");
+ break;
+ case "define":
+ System.out.println("\tAdd a macro rewrite directive.");
+ System.out.println("\tdefine <priority> <type> <recursion> <guard> <circular> <patterns>...");
+ break;
+ default:
+ System.out.println("\tNo help available for pragma " + pragma);
+ }
+
+ // Help always works
+ return true;
+ }
+
+ /*
+ * Matches slash-delimited strings
+ * (like /text/ or /text\/text/)
+ * Uses the "normal* (special normal*)*" pattern style
+ * recommended in 'Mastering regular expressions'
+ * Here, the normal is 'anything but a forward or backslash'
+ * (in regex, thats '[^/\\]') and the special is 'an escaped forward slash'
+ * (in regex, thats '\\\\/')
+ *
+ * Then, we just follow the pattern, escape it for java strings, and
+ * add the enclosing slashes
+ */
+ private Pattern slashPattern = Pattern.compile("/((?:\\\\.|[^/\\\\])*)/");
+
+ private boolean defineMode(String defineText) {
+ int firstIndex = defineText.indexOf(' ');
+ int secondIndex = defineText.indexOf(' ', firstIndex + 1);
+ int thirdIndex = defineText.indexOf(' ', secondIndex + 1);
+ int fourthIndex = defineText.indexOf(' ', thirdIndex + 1);
+ int fifthIndex = defineText.indexOf(' ', fourthIndex + 1);
+ int sixthIndex = defineText.indexOf(' ', fifthIndex + 1);
+
+ if(firstIndex == -1) {
+ Errors.inst.printError(EK_CONS_INVDEFINE, "(no priority)");
+ return false;
+ } else if(secondIndex == -1) {
+ Errors.inst.printError(EK_CONS_INVDEFINE, "(no define type)");
+ return false;
+ } else if(thirdIndex == -1) {
+ Errors.inst.printError(EK_CONS_INVDEFINE, "(no recursion type)");
+ return false;
+ } else if(fourthIndex == -1) {
+ Errors.inst.printError(EK_CONS_INVDEFINE, "(no guard type)");
+ return false;
+ } else if(fifthIndex == -1) {
+ Errors.inst.printError(EK_CONS_INVDEFINE, "(no circularity)");
+ return false;
+ } else if(sixthIndex == -1) {
+ Errors.inst.printError(EK_CONS_INVDEFINE, "(no patterns)");
+ return false;
+ }
+
+ int priority = Integer.parseInt(defineText.substring(0, firstIndex));
+
+ String defineType = defineText.substring(firstIndex + 1, secondIndex);
+
+ Define.Type type;
+ boolean subMode = false;
+
+ switch(defineType) {
+ case "line":
+ type = Define.Type.LINE;
+ break;
+ case "token":
+ type = Define.Type.TOKEN;
+ break;
+ case "subline":
+ type = Define.Type.LINE;
+ subMode = true;
+ break;
+ case "subtoken":
+ type = Define.Type.TOKEN;
+ subMode = true;
+ break;
+ default:
+ Errors.inst.printError(EK_CONS_INVDEFINE, "(unknown type)");
+ return false;
+ }
+
+ boolean doRecur = defineText.substring(secondIndex + 1, thirdIndex)
+ .equalsIgnoreCase("true");
+ boolean hasGuard = defineText.substring(thirdIndex + 1, fourthIndex)
+ .equalsIgnoreCase("true");
+ boolean isCircular = defineText.substring(thirdIndex + 1, fourthIndex)
+ .equalsIgnoreCase("true");
+
+ String pats = defineText.substring(fifthIndex + 1).trim();
+ Matcher patMatcher = slashPattern.matcher(pats);
+
+ String guardPattern = null;
+
+ if(hasGuard) {
+ if(!patMatcher.find()) {
+ Errors.inst.printError(EK_CONS_INVDEFINE, "(no guard pattern)");
+ return false;
+ }
+
+ guardPattern = patMatcher.group(1);
+ }
+
+ if(!patMatcher.find()) {
+ Errors.inst.printError(EK_CONS_INVDEFINE, "(no search pattern)");
+ return false;
+ }
+
+ String searchPattern = patMatcher.group(1);
+ List<String> replacePatterns = new LinkedList<>();
+
+ while(patMatcher.find()) {
+ replacePatterns.add(patMatcher.group(1));
+ }
+
+ Define dfn = new Define(priority, subMode, doRecur, isCircular,
+ guardPattern, searchPattern, replacePatterns);
+
+ if(dfn.inError) return false;
+
+ if(type == Define.Type.LINE) {
+ eng.addLineDefine(dfn);
+ } else {
+ eng.addTokenDefine(dfn);
+ }
+
+ return true;
+ }
+
+ public static void main(String[] args) {
+ DiceLangConsole console = new DiceLangConsole(args);
+
+ console.run();
+ }
+}