diff --git a/src/main/kotlin/function/builtin/LOAD.java b/src/main/kotlin/function/builtin/LOAD.java index 3892be9..d512990 100644 --- a/src/main/kotlin/function/builtin/LOAD.java +++ b/src/main/kotlin/function/builtin/LOAD.java @@ -10,6 +10,7 @@ import parser.LispParser; import sexpression.Cons; import sexpression.LispString; import sexpression.SExpression; +import util.Path; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -19,7 +20,6 @@ import static function.builtin.EVAL.eval; import static java.text.MessageFormat.format; import static sexpression.Nil.NIL; import static sexpression.Symbol.T; -import static util.Path.getPathPrefix; @FunctionNames({ "LOAD" }) public class LOAD extends LispFunction { @@ -80,7 +80,7 @@ public class LOAD extends LispFunction { } private boolean isSuccessfulEvaluationWithPathPrefix(String prefixedFileName, LispParser parser) { - pathPrefixes.push(getPathPrefix(prefixedFileName)); + pathPrefixes.push(Path.INSTANCE.getPathPrefix(prefixedFileName)); boolean isSuccessful = isSuccessfulEvaluation(parser); pathPrefixes.pop(); diff --git a/src/main/kotlin/interpreter/LispInterpreterBuilderImpl.java b/src/main/kotlin/interpreter/LispInterpreterBuilderImpl.java index 921fb1f..405ae83 100644 --- a/src/main/kotlin/interpreter/LispInterpreterBuilderImpl.java +++ b/src/main/kotlin/interpreter/LispInterpreterBuilderImpl.java @@ -4,6 +4,7 @@ import environment.RuntimeEnvironment; import error.CriticalLispException; import error.ErrorManager; import interpreter.LispInterpreter.LanguageFile; +import util.Path; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -13,8 +14,6 @@ import java.util.ArrayList; import java.util.List; import java.util.function.Function; -import static util.Path.getPathPrefix; - public class LispInterpreterBuilderImpl implements LispInterpreterBuilder { private static LispInterpreterBuilder uniqueInstance = new LispInterpreterBuilderImpl(); @@ -162,7 +161,7 @@ public class LispInterpreterBuilderImpl implements LispInterpreterBuilder { private void configurePath() { if (isFileBased) - environment.setPath(getPathPrefix(inputName)); + environment.setPath(Path.INSTANCE.getPathPrefix(inputName)); else environment.setPath(""); } diff --git a/src/main/kotlin/scanner/LispCommentRemovingInputStream.java b/src/main/kotlin/scanner/LispCommentRemovingInputStream.java index 5155978..7aa2fe8 100644 --- a/src/main/kotlin/scanner/LispCommentRemovingInputStream.java +++ b/src/main/kotlin/scanner/LispCommentRemovingInputStream.java @@ -1,15 +1,10 @@ package scanner; import stream.SafeInputStream; +import util.Characters; import java.io.InputStream; -import static util.Characters.BACKSLASH; -import static util.Characters.DOUBLE_QUOTE; -import static util.Characters.EOF; -import static util.Characters.NEWLINE; -import static util.Characters.SEMICOLON; - /** * Removes Lisp comments from an input stream. */ @@ -57,11 +52,11 @@ public class LispCommentRemovingInputStream implements LispInputStream { } private boolean haveEncounteredStringBoundary() { - return (previousCharacter != BACKSLASH) && (currentCharacter == DOUBLE_QUOTE); + return (previousCharacter != Characters.BACKSLASH) && (currentCharacter == Characters.DOUBLE_QUOTE); } private boolean haveEnteredComment() { - return (currentCharacter == SEMICOLON) && (!isInQuotedString); + return (currentCharacter == Characters.SEMICOLON) && (!isInQuotedString); } private void consumeAllBytesInComment() { @@ -70,7 +65,7 @@ public class LispCommentRemovingInputStream implements LispInputStream { } private boolean stillInComment() { - return (currentCharacter != NEWLINE) && (currentCharacter != EOF); + return (currentCharacter != Characters.NEWLINE) && (currentCharacter != Characters.EOF); } @Override diff --git a/src/main/kotlin/scanner/LispScanner.java b/src/main/kotlin/scanner/LispScanner.java index 8d267c3..74efabb 100644 --- a/src/main/kotlin/scanner/LispScanner.java +++ b/src/main/kotlin/scanner/LispScanner.java @@ -13,12 +13,6 @@ import java.util.function.Function; import static java.lang.Character.isDigit; import static java.lang.Character.isWhitespace; -import static util.Characters.BACKSLASH; -import static util.Characters.DOUBLE_QUOTE; -import static util.Characters.EOF; -import static util.Characters.NEWLINE; -import static util.Characters.isLegalIdentifierCharacter; -import static util.Characters.isNumberPrefix; /** * Converts a stream of bytes into a stream of Lisp tokens. @@ -36,13 +30,13 @@ public class LispScanner { } public Token getNextToken() { - for (int c = inputStream.read(); c != EOF; c = inputStream.read()) { + for (int c = inputStream.read(); c != Characters.EOF; c = inputStream.read()) { char currentCharacter = (char) c; positionTracker.incrementColumn(); if (!isWhitespace(currentCharacter)) return createTokenFromCharacter(currentCharacter); - else if (currentCharacter == NEWLINE) + else if (currentCharacter == Characters.NEWLINE) positionTracker.incrementLine(); } @@ -59,13 +53,13 @@ public class LispScanner { private String retrieveTokenText(char firstCharacter) { String tokenText = "" + firstCharacter; - if (firstCharacter == DOUBLE_QUOTE) + if (firstCharacter == Characters.DOUBLE_QUOTE) tokenText = retrieveStringTokenText(firstCharacter); - else if (isNumberPrefix(firstCharacter)) + else if (Characters.INSTANCE.isNumberPrefix(firstCharacter)) tokenText = retrieveNumberOrIdentifierTokenText(firstCharacter); else if (isDigit(firstCharacter)) tokenText = retrieveNumberTokenText(firstCharacter); - else if (isLegalIdentifierCharacter(firstCharacter)) + else if (Characters.INSTANCE.isLegalIdentifierCharacter(firstCharacter)) tokenText = retrieveIdentifierTokenText(firstCharacter); return tokenText; @@ -73,7 +67,7 @@ public class LispScanner { private String retrieveStringTokenText(char firstDoubleQuote) { ComplexTokenTextRetriever retriever = new ComplexTokenTextRetriever(firstDoubleQuote, - Characters::isLegalStringCharacter); + Characters.INSTANCE::isLegalStringCharacter); return retriever.retrieveToken(); } @@ -96,7 +90,7 @@ public class LispScanner { private String retrieveIdentifierTokenText(char firstCharacter) { ComplexTokenTextRetriever retriever = new ComplexTokenTextRetriever(firstCharacter, - Characters::isLegalIdentifierCharacter); + Characters.INSTANCE::isLegalIdentifierCharacter); return retriever.retrieveToken(); } @@ -122,7 +116,7 @@ public class LispScanner { public String retrieveToken() { text.append(firstCharacter); - for (int c = inputStream.read(); c != EOF; c = inputStream.read()) { + for (int c = inputStream.read(); c != Characters.EOF; c = inputStream.read()) { currentCharacter = (char) c; if (!isPartOfToken.apply(currentCharacter)) { @@ -146,7 +140,7 @@ public class LispScanner { text.append(currentCharacter); positionTracker.incrementColumn(); - if (currentCharacter == NEWLINE) + if (currentCharacter == Characters.NEWLINE) positionTracker.incrementLine(); } @@ -155,11 +149,12 @@ public class LispScanner { } private boolean isStringToken() { - return firstCharacter == DOUBLE_QUOTE; + return firstCharacter == Characters.DOUBLE_QUOTE; } private boolean isTerminatingDoubleQuote() { - return (currentCharacter == DOUBLE_QUOTE) && (previousCharacter != BACKSLASH); + return (currentCharacter == Characters.DOUBLE_QUOTE) && + (previousCharacter != Characters.BACKSLASH); } private String terminateTokenWithEof() { diff --git a/src/main/kotlin/table/FunctionTable.kt b/src/main/kotlin/table/FunctionTable.kt index 81c628d..dcf53d9 100644 --- a/src/main/kotlin/table/FunctionTable.kt +++ b/src/main/kotlin/table/FunctionTable.kt @@ -56,7 +56,7 @@ import java.util.HashSet object FunctionTable { - private var table: MutableMap = HashMap() + private var table = HashMap() private val allBuiltIns = HashSet>() init { @@ -154,6 +154,6 @@ object FunctionTable { class LispFunctionInstantiationException(private val functionName: String) : CriticalLispException() { override val message: String - get() = format("Could not create an instance of ''{0}''", functionName) + get() = "Could not create an instance of '$functionName'" } } diff --git a/src/main/kotlin/terminal/ControlSequenceHandler.java b/src/main/kotlin/terminal/ControlSequenceHandler.java index 51e5cd0..4f072a8 100644 --- a/src/main/kotlin/terminal/ControlSequenceHandler.java +++ b/src/main/kotlin/terminal/ControlSequenceHandler.java @@ -1,16 +1,14 @@ package terminal; import stream.SafeInputStream; +import util.Characters; import static java.lang.Character.isDigit; -import static util.Characters.EOF; -import static util.Characters.LEFT_SQUARE_BRACKET; -import static util.Characters.UNICODE_ESCAPE; class ControlSequenceHandler { public static final boolean isEscape(char c) { - return c == UNICODE_ESCAPE; + return c == Characters.UNICODE_ESCAPE; } private ControlSequenceLookup controlSequenceLookup; @@ -42,11 +40,11 @@ class ControlSequenceHandler { } private boolean isCharacter() { - return currentCharacter != EOF; + return currentCharacter != Characters.EOF; } private boolean isLeftBracket() { - return (char) currentCharacter == LEFT_SQUARE_BRACKET; + return (char) currentCharacter == Characters.LEFT_SQUARE_BRACKET; } private void readCode() { diff --git a/src/main/kotlin/terminal/LispTerminal.java b/src/main/kotlin/terminal/LispTerminal.java index 99dee32..9fb0ed6 100644 --- a/src/main/kotlin/terminal/LispTerminal.java +++ b/src/main/kotlin/terminal/LispTerminal.java @@ -7,6 +7,7 @@ import com.googlecode.lanterna.input.KeyType; import com.googlecode.lanterna.terminal.IOSafeTerminal; import stream.SafeInputStream; import stream.SafeOutputStream; +import util.Characters; import java.io.ByteArrayInputStream; import java.util.concurrent.ExecutorService; @@ -21,12 +22,10 @@ import static com.googlecode.lanterna.input.KeyType.Character; import static com.googlecode.lanterna.input.KeyType.Delete; import static com.googlecode.lanterna.input.KeyType.Enter; import static terminal.ControlSequenceHandler.isEscape; -import static util.Characters.EOF; -import static util.Characters.UNICODE_NULL; public class LispTerminal { - public static final char END_OF_SEGMENT = UNICODE_NULL; + public static final char END_OF_SEGMENT = Characters.UNICODE_NULL; private IOSafeTerminal terminal; private SafeOutputStream inputWriter; @@ -397,7 +396,7 @@ public class LispTerminal { } private void writeOutput() { - for (int c = outputReader.read(); c != EOF; c = outputReader.read()) + for (int c = outputReader.read(); c != Characters.EOF; c = outputReader.read()) processOutput((char) c); terminal.flush(); @@ -431,7 +430,7 @@ public class LispTerminal { private synchronized void putOutputToTerminal() { SafeInputStream input = convertOutputToStream(); - for (int c = input.read(); c != EOF; c = input.read()) + for (int c = input.read(); c != Characters.EOF; c = input.read()) if (isEscape((char) c)) applyControlSequence(input); else diff --git a/src/main/kotlin/token/TokenFactoryImpl.java b/src/main/kotlin/token/TokenFactoryImpl.java index 93a47ea..c5edf1a 100644 --- a/src/main/kotlin/token/TokenFactoryImpl.java +++ b/src/main/kotlin/token/TokenFactoryImpl.java @@ -1,17 +1,9 @@ package token; import file.FilePosition; +import util.Characters; import static java.lang.Character.isDigit; -import static util.Characters.AT_SIGN; -import static util.Characters.BACKQUOTE; -import static util.Characters.COMMA; -import static util.Characters.DOUBLE_QUOTE; -import static util.Characters.LEFT_PARENTHESIS; -import static util.Characters.RIGHT_PARENTHESIS; -import static util.Characters.SINGLE_QUOTE; -import static util.Characters.isLegalIdentifierCharacter; -import static util.Characters.isNumberPrefix; public class TokenFactoryImpl implements TokenFactory { @@ -23,24 +15,24 @@ public class TokenFactoryImpl implements TokenFactory { char firstCharacter = text.charAt(0); switch (firstCharacter) { - case LEFT_PARENTHESIS: + case Characters.LEFT_PARENTHESIS: return new LeftParenthesis(text, position); - case RIGHT_PARENTHESIS: + case Characters.RIGHT_PARENTHESIS: return new RightParenthesis(text, position); - case SINGLE_QUOTE: + case Characters.SINGLE_QUOTE: return new QuoteMark(text, position); - case DOUBLE_QUOTE: + case Characters.DOUBLE_QUOTE: return new QuotedString(text, position); - case BACKQUOTE: + case Characters.BACKQUOTE: return new Backquote(text, position); - case AT_SIGN: + case Characters.AT_SIGN: return new AtSign(text, position); - case COMMA: + case Characters.COMMA: return new Comma(text, position); default: if (isNumeric(firstCharacter, text)) return new Number(text, position); - else if (isLegalIdentifierCharacter(firstCharacter)) + else if (Characters.INSTANCE.isLegalIdentifierCharacter(firstCharacter)) return new Identifier(text, position); } @@ -52,7 +44,7 @@ public class TokenFactoryImpl implements TokenFactory { } private boolean isPrefixedNumeric(char firstCharacter, String text) { - return isNumberPrefix(firstCharacter) && isNextCharacterDigit(text); + return Characters.INSTANCE.isNumberPrefix(firstCharacter) && isNextCharacterDigit(text); } private boolean isNextCharacterDigit(String text) { diff --git a/src/main/kotlin/util/Characters.java b/src/main/kotlin/util/Characters.java deleted file mode 100644 index 7a3a2e9..0000000 --- a/src/main/kotlin/util/Characters.java +++ /dev/null @@ -1,60 +0,0 @@ -package util; - -import java.util.HashSet; -import java.util.Set; - -public final class Characters { - - private Characters() {} - - public static final int EOF = -1; - - public static final char AT_SIGN = '@'; - public static final char BACKQUOTE = '`'; - public static final char BACKSLASH = '\\'; - public static final char COMMA = ','; - public static final char DASH = '-'; - public static final char DOUBLE_QUOTE = '\"'; - public static final char HASH = '#'; - public static final char LEFT_PARENTHESIS = '('; - public static final char LEFT_SQUARE_BRACKET = '['; - public static final char NEWLINE = '\n'; - public static final char PERIOD = '.'; - public static final char PLUS = '+'; - public static final char RIGHT_PARENTHESIS = ')'; - public static final char RIGHT_SQUARE_BRACKET = ']'; - public static final char SEMICOLON = ';'; - public static final char SINGLE_QUOTE = '\''; - public static final char UNICODE_ESCAPE = '\u001B'; - public static final char UNICODE_NULL = '\u0000'; - - public static final Set illegalIdentifierCharacters = new HashSet<>(); - - static { - illegalIdentifierCharacters.add(AT_SIGN); - illegalIdentifierCharacters.add(BACKQUOTE); - illegalIdentifierCharacters.add(BACKSLASH); - illegalIdentifierCharacters.add(COMMA); - illegalIdentifierCharacters.add(DOUBLE_QUOTE); - illegalIdentifierCharacters.add(HASH); - illegalIdentifierCharacters.add(LEFT_PARENTHESIS); - illegalIdentifierCharacters.add(LEFT_SQUARE_BRACKET); - illegalIdentifierCharacters.add(PERIOD); - illegalIdentifierCharacters.add(RIGHT_PARENTHESIS); - illegalIdentifierCharacters.add(RIGHT_SQUARE_BRACKET); - illegalIdentifierCharacters.add(SEMICOLON); - illegalIdentifierCharacters.add(SINGLE_QUOTE); - } - - public static boolean isLegalIdentifierCharacter(char c) { - return (!Character.isWhitespace(c)) && (!illegalIdentifierCharacters.contains(c)); - } - - public static boolean isLegalStringCharacter(char c) { - return true; - } - - public static boolean isNumberPrefix(char c) { - return c == DASH || c == PLUS; - } -} diff --git a/src/main/kotlin/util/Characters.kt b/src/main/kotlin/util/Characters.kt new file mode 100644 index 0000000..c5a19a8 --- /dev/null +++ b/src/main/kotlin/util/Characters.kt @@ -0,0 +1,48 @@ +package util + +import java.util.HashSet + +object Characters { + + const val EOF = -1 + const val AT_SIGN = '@' + const val BACKQUOTE = '`' + const val BACKSLASH = '\\' + const val COMMA = ',' + const val DASH = '-' + const val DOUBLE_QUOTE = '\"' + const val HASH = '#' + const val LEFT_PARENTHESIS = '(' + const val LEFT_SQUARE_BRACKET = '[' + const val NEWLINE = '\n' + const val PERIOD = '.' + const val PLUS = '+' + const val RIGHT_PARENTHESIS = ')' + const val RIGHT_SQUARE_BRACKET = ']' + const val SEMICOLON = ';' + const val SINGLE_QUOTE = '\'' + const val UNICODE_ESCAPE = '\u001B' + const val UNICODE_NULL = '\u0000' + + private val illegalIdentifierCharacters = HashSet() + + init { + illegalIdentifierCharacters.add(AT_SIGN) + illegalIdentifierCharacters.add(BACKQUOTE) + illegalIdentifierCharacters.add(BACKSLASH) + illegalIdentifierCharacters.add(COMMA) + illegalIdentifierCharacters.add(DOUBLE_QUOTE) + illegalIdentifierCharacters.add(HASH) + illegalIdentifierCharacters.add(LEFT_PARENTHESIS) + illegalIdentifierCharacters.add(LEFT_SQUARE_BRACKET) + illegalIdentifierCharacters.add(PERIOD) + illegalIdentifierCharacters.add(RIGHT_PARENTHESIS) + illegalIdentifierCharacters.add(RIGHT_SQUARE_BRACKET) + illegalIdentifierCharacters.add(SEMICOLON) + illegalIdentifierCharacters.add(SINGLE_QUOTE) + } + + fun isLegalIdentifierCharacter(c: Char) = !Character.isWhitespace(c) && !illegalIdentifierCharacters.contains(c) + fun isLegalStringCharacter(c: Char) = true + fun isNumberPrefix(c: Char) = c == DASH || c == PLUS +} diff --git a/src/main/kotlin/util/Path.java b/src/main/kotlin/util/Path.java deleted file mode 100644 index c845e8e..0000000 --- a/src/main/kotlin/util/Path.java +++ /dev/null @@ -1,12 +0,0 @@ -package util; - -import java.io.File; - -public final class Path { - - private Path() {} - - public static String getPathPrefix(String fileName) { - return fileName.substring(0, fileName.lastIndexOf(File.separator) + 1); - } -} diff --git a/src/main/kotlin/util/Path.kt b/src/main/kotlin/util/Path.kt new file mode 100644 index 0000000..ed99f66 --- /dev/null +++ b/src/main/kotlin/util/Path.kt @@ -0,0 +1,8 @@ +package util + +import java.io.File + +object Path { + + fun getPathPrefix(fileName: String) = fileName.substring(0, fileName.lastIndexOf(File.separator) + 1) +} diff --git a/src/test/kotlin/acceptance/fixture/LispInterpreterFixture.java b/src/test/kotlin/acceptance/fixture/LispInterpreterFixture.java index f3f099a..307285d 100644 --- a/src/test/kotlin/acceptance/fixture/LispInterpreterFixture.java +++ b/src/test/kotlin/acceptance/fixture/LispInterpreterFixture.java @@ -6,6 +6,7 @@ import interpreter.LispInterpreterBuilder; import interpreter.LispInterpreterBuilderImpl; import table.ExecutionContext; import table.FunctionTable; +import util.Path; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -14,7 +15,6 @@ import java.io.FileNotFoundException; import java.io.PrintStream; import static application.LispMain.LANGUAGE_FILE_NAMES; -import static util.Path.getPathPrefix; public class LispInterpreterFixture { @@ -63,7 +63,7 @@ public class LispInterpreterFixture { public String evaluateFile(String inputFile) throws FileNotFoundException { environment.setInputName(inputFile); environment.setInput(new FileInputStream(inputFile)); - environment.setPath(getPathPrefix(inputFile)); + environment.setPath(Path.INSTANCE.getPathPrefix(inputFile)); return evaluate(); } diff --git a/src/test/kotlin/util/CharactersTest.java b/src/test/kotlin/util/CharactersTest.java deleted file mode 100644 index a0c4907..0000000 --- a/src/test/kotlin/util/CharactersTest.java +++ /dev/null @@ -1,21 +0,0 @@ -package util; - -import org.junit.Test; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Modifier; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; - -public class CharactersTest { - - @Test - public void constructorIsPrivate() throws Exception { - Constructor constructor = Characters.class.getDeclaredConstructor(); - - assertThat(Modifier.isPrivate(constructor.getModifiers()), is(true)); - constructor.setAccessible(true); - constructor.newInstance(); - } -} diff --git a/src/test/kotlin/util/PathTest.java b/src/test/kotlin/util/PathTest.java deleted file mode 100644 index 64ee966..0000000 --- a/src/test/kotlin/util/PathTest.java +++ /dev/null @@ -1,21 +0,0 @@ -package util; - -import org.junit.Test; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Modifier; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; - -public class PathTest { - - @Test - public void constructorIsPrivate() throws Exception { - Constructor constructor = Path.class.getDeclaredConstructor(); - - assertThat(Modifier.isPrivate(constructor.getModifiers()), is(true)); - constructor.setAccessible(true); - constructor.newInstance(); - } -}