diff options
| author | Benjamin J. Culkin <bjculkin@mix.wvu.edu> | 2017-10-25 12:10:14 -0300 |
|---|---|---|
| committer | Benjamin J. Culkin <bjculkin@mix.wvu.edu> | 2017-10-25 12:10:14 -0300 |
| commit | 7bda9de511a5642efb297eae98c6ea7c42b27754 (patch) | |
| tree | dff1aa772b9ac088c5bd07b8d10d944cbff89f96 /dice-lang/src/bjc/dicelang/scl | |
| parent | f028ea6dc555fc5192a96b00b8e96e90dbf6de55 (diff) | |
Start switch to maven modules
Diffstat (limited to 'dice-lang/src/bjc/dicelang/scl')
| -rw-r--r-- | dice-lang/src/bjc/dicelang/scl/StreamControlConsole.java | 75 | ||||
| -rw-r--r-- | dice-lang/src/bjc/dicelang/scl/StreamControlEngine.java | 546 | ||||
| -rw-r--r-- | dice-lang/src/bjc/dicelang/scl/StreamEngine.java | 266 |
3 files changed, 0 insertions, 887 deletions
diff --git a/dice-lang/src/bjc/dicelang/scl/StreamControlConsole.java b/dice-lang/src/bjc/dicelang/scl/StreamControlConsole.java deleted file mode 100644 index 649c6fa..0000000 --- a/dice-lang/src/bjc/dicelang/scl/StreamControlConsole.java +++ /dev/null @@ -1,75 +0,0 @@ -package bjc.dicelang.scl; - -import bjc.utils.funcdata.FunctionalList; -import bjc.utils.funcdata.IList; - -import java.util.Iterator; -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 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); - - /* 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().trim(); - - if (ln.equals("")) { - /* Ignore empty lines. */ - break; - } - - /* Break the token into strings. */ - IList<String> res = new FunctionalList<>(); - String[] tokens = ln.split(" "); - - /* 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; - } - - /* Prompt again. */ - System.out.print("Command string executed succesfully.\n\n"); - System.out.print("Enter a SCL command string (blank to exit): "); - } - } -} diff --git a/dice-lang/src/bjc/dicelang/scl/StreamControlEngine.java b/dice-lang/src/bjc/dicelang/scl/StreamControlEngine.java deleted file mode 100644 index d5e8b72..0000000 --- a/dice-lang/src/bjc/dicelang/scl/StreamControlEngine.java +++ /dev/null @@ -1,546 +0,0 @@ -package bjc.dicelang.scl; - -import java.util.HashMap; -import java.util.Map; - -import bjc.dicelang.Errors; -import bjc.utils.esodata.SimpleStack; -import bjc.utils.esodata.Stack; -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 { - /* - * @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 */ - ILIT, FLIT, BLIT, SQUOTE, DQUOTE, OBRACKET, OBRACE, SYMBOL, WORD, - - /* Synthetic tokens. These are produced from special tokens. */ - SLIT, WORDS, ARRAY, - - /* Word tokens These are subordinate to WORD tokens */ - /* - * @NOTE - * These should really be in their own enum. - */ - /* Array manipulation */ - MAKEARRAY, MAKEEXEC, MAKEUNEXEC, - /* Stream manipulation */ - NEWSTREAM, LEFTSTREAM, RIGHTSTREAM, DELETESTREAM, MERGESTREAM, - /* Stack manipulation */ - STACKCOUNT, STACKEMPTY, DROP, NDROP, NIP, NNIP, - } - - /* The type of this token */ - public Type type; - - /* Used for ILIT */ - public long intVal; - /* Used for FLIT */ - public double floatVal; - /* Used for BLIT */ - public boolean boolVal; - /* Used for SYMBOL & SLIT */ - public String stringVal; - /* Used for WORD */ - public Token tokenVal; - /* 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)); - } else if (token.startsWith("\\")) { - return new Token(SYMBOL, token.substring(1)); - } else if (builtinWords.containsKey(token)) { - return new Token(WORD, builtinWords.get(token)); - } else if (token.equals("true")) { - return new Token(BLIT, true); - } else if (token.equals("false")) { - return new Token(BLIT, false); - } else if (TokenUtils.isInt(token)) { - return new Token(ILIT, Long.parseLong(token)); - } else if (TokenUtils.isDouble(token)) { - return new Token(FLIT, Double.parseDouble(token)); - } else { - Errors.inst.printError(EK_SCL_INVTOKEN, token); - return null; - } - } - - /* 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); - litTokens.put("\"", DQUOTE); - litTokens.put("[", OBRACKET); - litTokens.put("{", OBRACE); - - /* Init builtin words. */ - builtinWords = new HashMap<>(); - - builtinWords.put("makearray", MAKEARRAY); - builtinWords.put("+stream", NEWSTREAM); - builtinWords.put(">stream", LEFTSTREAM); - builtinWords.put("<stream", RIGHTSTREAM); - builtinWords.put("-stream", DELETESTREAM); - builtinWords.put("<-stream", MERGESTREAM); - builtinWords.put("cvx", MAKEEXEC); - builtinWords.put("cvux", MAKEUNEXEC); - builtinWords.put("#", STACKCOUNT); - builtinWords.put("empty?", STACKEMPTY); - builtinWords.put("drop", DROP); - builtinWords.put("ndrop", NDROP); - builtinWords.put("nip", NIP); - builtinWords.put("nnip", NNIP); - } - } - - /* The stream engine we're hooked to. */ - private final StreamEngine eng; - - /* The current stack state. */ - private final Stack<Token> curStack; - - /* Map of user defined words. */ - private final Map<String, Token> words; - - /** - * Create a new stream control engine. - * - * @param engine - * The engine to control. - */ - public StreamControlEngine(final StreamEngine engine) { - eng = engine; - - words = new HashMap<>(); - curStack = new SimpleStack<>(); - } - - /** - * Run a SCL program. - * - * @param tokens - * The program to run. - * - * @return Whether the program executed successfully. - */ - 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); - - 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: - /* 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; - } - } - - return true; - } - - 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; - } - - return true; - } - - /* Handle nipping a specified number of items. */ - private boolean handleNNip() { - final Token num = curStack.pop(); - - if (num.type != ILIT) { - Errors.inst.printError(EK_SCL_INVARG, num.type.toString()); - return false; - } - - final int n = (int) num.intVal; - - if (curStack.size() < n) { - Errors.inst.printError(EK_SCL_SUNDERFLOW, NNIP.toString()); - return false; - } - - curStack.nip(n); - return true; - } - - /* Handle dropping a specified number of items. */ - private boolean handleNDrop() { - final Token num = curStack.pop(); - - if (num.type != ILIT) { - Errors.inst.printError(EK_SCL_INVARG, num.type.toString()); - return false; - } - - final int n = (int) num.intVal; - - if (curStack.size() < n) { - Errors.inst.printError(EK_SCL_SUNDERFLOW, NDROP.toString()); - return false; - } - - curStack.drop(n); - return true; - } - - /* Handle toggling the executable flag on an array. */ - private boolean toggleExec(final boolean exec) { - final Token top = curStack.top(); - - if (exec) { - if (top.type != ARRAY) { - Errors.inst.printError(EK_SCL_INVARG, top.toString()); - return false; - } - - top.type = WORDS; - } else { - if (top.type != WORDS) { - Errors.inst.printError(EK_SCL_INVARG, top.toString()); - return false; - } - - top.type = ARRAY; - } - - return true; - } - - /* Handle creating an array. */ - private boolean makeArray() { - final Token num = curStack.pop(); - - if (num.type != ILIT) { - Errors.inst.printError(EK_SCL_INVARG, num.type.toString()); - } - - final IList<Token> arr = new FunctionalList<>(); - - for (int i = 0; i < num.intVal; i++) { - arr.add(curStack.pop()); - } - - curStack.push(new Token(ARRAY, arr)); - - 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<>(); - - int n = i + 1; - - if (n >= tokens.length) { - Errors.inst.printError(EK_SCL_MMQUOTE); - return -1; - } - - String tok = tokens[n]; - - while (!tok.equals(delim)) { - final Token ntok = Token.tokenizeString(tok); - - switch (ntok.type) { - case SQUOTE: - n = handleSingleQuote(n, tokens); - if (n == -1) { - return -1; - } - toks.add(curStack.pop()); - break; - case OBRACKET: - n = handleDelim(n, tokens, "]"); - if (n == -1) { - return -1; - } - toks.add(curStack.pop()); - break; - case OBRACE: - n = handleDelim(i, tokens, "}"); - if (n == -1) { - return -1; - } - final Token brak = curStack.pop(); - toks.add(new Token(ARRAY, brak.tokenVals)); - break; - default: - toks.add(ntok); - } - - /* Move to the next token */ - n += 1; - - if (n >= tokens.length) { - Errors.inst.printError(EK_SCL_MMQUOTE); - return -1; - } - - tok = tokens[n]; - } - - /* 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(); - - int n = i + 1; - - if (n >= tokens.length) { - Errors.inst.printError(EK_SCL_MMQUOTE); - return -1; - } - - String tok = tokens[n]; - - while (!tok.equals("'")) { - if (tok.matches("\\\\+'")) { - /* Handle escaped quotes. */ - sb.append(tok.substring(1)); - } else { - sb.append(tok); - } - - /* Move to the next token */ - n += 1; - - if (n >= tokens.length) { - Errors.inst.printError(EK_SCL_MMQUOTE); - return -1; - } - - tok = tokens[n]; - } - - /* - * Skip the single quote - */ - n += 1; - - curStack.push(new Token(SLIT, TokenUtils.descapeString(sb.toString()))); - - return n; - } -} diff --git a/dice-lang/src/bjc/dicelang/scl/StreamEngine.java b/dice-lang/src/bjc/dicelang/scl/StreamEngine.java deleted file mode 100644 index 6e970b7..0000000 --- a/dice-lang/src/bjc/dicelang/scl/StreamEngine.java +++ /dev/null @@ -1,266 +0,0 @@ -package bjc.dicelang.scl; - -import static bjc.dicelang.Errors.ErrorKey.EK_STRM_INVCOM; -import static bjc.dicelang.Errors.ErrorKey.EK_STRM_LAST; -import static bjc.dicelang.Errors.ErrorKey.EK_STRM_NONEX; - -import static java.util.logging.Level.*; - -import bjc.dicelang.DiceLangEngine; -import bjc.dicelang.Errors; -import bjc.utils.esodata.SingleTape; -import bjc.utils.esodata.Tape; -import bjc.utils.esodata.TapeLibrary; -import bjc.utils.funcdata.FunctionalList; -import bjc.utils.funcdata.IList; -import bjc.utils.funcutils.ListUtils; - -import java.util.Arrays; - -/** - * Implements multiple interleaved parse streams, as well as a command language - * for the streams. - * - * The idea for the interleaved streams came from the language Oozylbub & - * Murphy, but the command language was my own idea. - * - * @author Ben Culkin - */ -public class StreamEngine { - /* Whether or not we're doing debugging. */ - public final boolean debug = true; - - /* The engine we're attached to. */ - DiceLangEngine eng; - - /* Our streams. */ - Tape<IList<String>> streams; - IList<String> currStream; - - /* Saved streams */ - TapeLibrary<IList<String>> savedStreams; - - /* Handler for SCL programs */ - private final StreamControlEngine scleng; - - /** - * Create a new stream engine. - * - * @param engine - * The dice engine we're attached to. - */ - public StreamEngine(final DiceLangEngine engine) { - eng = engine; - - savedStreams = new TapeLibrary<>(); - scleng = new StreamControlEngine(this); - } - - /* Do pre-run (re)initialization. */ - private void init() { - /* Reinitialize our list of streams. */ - streams = new SingleTape<>(); - - /* Create an initial stream. */ - currStream = new FunctionalList<>(); - streams.insertBefore(currStream); - } - - /** - * Process a possibly interleaved set of streams. - * - * @param toks - * The raw token to read streams from. - * - * @param dest - * The list to write the final stream to. - * - * @return Whether or not the streams were successfully processed. - */ - public boolean doStreams(final String[] toks, final IList<String> dest) { - return doStreams(Arrays.asList(toks), dest); - } - - /** - * Process a possibly interleaved set of streams. - * - * @param toks - * The raw token to read streams from. - * - * @param dest - * The list to write the final stream to. - * - * @return Whether or not the streams were successfully processed. - */ - public boolean doStreams(final Iterable<String> toks, final IList<String> dest) { - /* Initialize per-run state. */ - init(); - - /* Are we currently quoting things? */ - boolean quoteMode = false; - - /* Process each token. */ - for (final String tk : toks) { - /* Process stream commands. */ - if (tk.startsWith("{@S") && !quoteMode) { - 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); - } - } - } - - for (final String tk : currStream) { - /* Collect tokens from the current stream. */ - dest.add(tk); - } - - return true; - } - - /** Create a new stream. */ - public void newStream() { - streams.insertAfter(new FunctionalList<>()); - } - - /** - * Move to a stream to the right. - * - * @return Whether or not the move was successful. - */ - public boolean rightStream() { - if (!streams.right()) { - Errors.inst.printError(EK_STRM_NONEX); - return false; - } - - currStream = streams.item(); - return true; - } - - /** - * Move to a stream to the left. - * - * @return Whether or not the move was successful. - */ - public boolean leftStream() { - if (!streams.left()) { - Errors.inst.printError(EK_STRM_NONEX); - return false; - } - - currStream = streams.item(); - return true; - } - - /** - * Delete the current stream. - * - * @return Whether or not the delete succeeded. - */ - public boolean deleteStream() { - if (streams.size() == 1) { - Errors.inst.printError(EK_STRM_LAST); - return false; - } - - streams.remove(); - currStream = streams.item(); - - return true; - } - - /** - * Merge the current stream into the previous stream. - * - * @return Whether or not the merge succeded. - */ - public boolean mergeStream() { - if (streams.size() == 1) { - Errors.inst.printError(EK_STRM_LAST); - return false; - } - - final IList<String> stringLit = streams.remove(); - currStream = streams.item(); - currStream.add(ListUtils.collapseTokens(stringLit, " ")); - - return true; - } - - private boolean processCommand(final String tk) { - 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; - } - } - - return true; - } -} |
