Convert file position code to kotlin

This commit is contained in:
Mike Cifelli 2018-05-05 12:02:43 -04:00
parent 3664a58989
commit 61adaffd3c
15 changed files with 152 additions and 212 deletions

View File

@ -10,7 +10,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<kotlin.version>1.2.31</kotlin.version>
<kotlin.version>1.2.41</kotlin.version>
<junit5.version>5.1.0</junit5.version>
<skipTests>false</skipTests>
</properties>

View File

@ -6,21 +6,21 @@ enum class Severity {
WARNING {
override fun decorate(output: String, environment: RuntimeEnvironment): String =
RuntimeEnvironment.decorateWarningOutput(output)!!
RuntimeEnvironment.decorateWarningOutput(output)
override fun toDisplayString() = "warning"
},
ERROR {
override fun decorate(output: String, environment: RuntimeEnvironment): String =
RuntimeEnvironment.decorateErrorOutput(output)!!
RuntimeEnvironment.decorateErrorOutput(output)
override fun toDisplayString() = "error"
},
CRITICAL {
override fun decorate(output: String, environment: RuntimeEnvironment): String =
RuntimeEnvironment.decorateCriticalOutput(output)!!
RuntimeEnvironment.decorateCriticalOutput(output)
override fun toDisplayString() = "critical"
};

View File

@ -1,32 +0,0 @@
package file;
public class FilePosition {
private String fileName;
private int lineNumber;
private int columnNumber;
public FilePosition(String fileName) {
this.fileName = fileName;
}
public String getFileName() {
return fileName;
}
public int getLineNumber() {
return lineNumber;
}
public void setLineNumber(int lineNumber) {
this.lineNumber = lineNumber;
}
public int getColumnNumber() {
return columnNumber;
}
public void setColumnNumber(int columnNumber) {
this.columnNumber = columnNumber;
}
}

View File

@ -0,0 +1,3 @@
package file
data class FilePosition(val fileName: String, val lineNumber: Int, val columnNumber: Int)

View File

@ -1,31 +0,0 @@
package file;
public class FilePositionTracker {
private String fileName;
private int lineNumber;
private int columnNumber;
public FilePositionTracker(String fileName) {
this.fileName = fileName;
this.lineNumber = 1;
this.columnNumber = 0;
}
public FilePosition getCurrentPosition() {
FilePosition currentPosition = new FilePosition(fileName);
currentPosition.setLineNumber(lineNumber);
currentPosition.setColumnNumber(columnNumber);
return currentPosition;
}
public void incrementColumn() {
columnNumber++;
}
public void incrementLine() {
lineNumber++;
columnNumber = 0;
}
}

View File

@ -0,0 +1,18 @@
package file
class FilePositionTracker(private val fileName: String) {
private var lineNumber = 1
private var columnNumber = 0
fun currentPosition() = FilePosition(fileName = fileName, lineNumber = lineNumber, columnNumber = columnNumber)
fun incrementColumn() {
columnNumber++
}
fun incrementLine() {
lineNumber++
columnNumber = 0
}
}

View File

@ -77,7 +77,7 @@ object LispInterpreterBuilder {
this.languageFiles = ArrayList()
for (fileName in languageFiles)
this.languageFiles!!.add(LanguageFile(classLoader.getResourceAsStream(fileName), fileName))
this.languageFiles.add(LanguageFile(classLoader.getResourceAsStream(fileName), fileName))
}
fun setTerminationFunction(terminationFunction: () -> Unit) {
@ -135,7 +135,7 @@ object LispInterpreterBuilder {
private fun configurePath() {
if (isFileBased)
RuntimeEnvironment.path = Path.getPathPrefix(inputName!!)
RuntimeEnvironment.path = Path.getPathPrefix(inputName)
else
RuntimeEnvironment.path = ""
}

View File

@ -40,11 +40,11 @@ public class LispScanner {
positionTracker.incrementLine();
}
return tokenFactory.createEofToken(positionTracker.getCurrentPosition());
return tokenFactory.createEofToken(positionTracker.currentPosition());
}
private Token createTokenFromCharacter(char c) {
FilePosition currentPosition = positionTracker.getCurrentPosition();
FilePosition currentPosition = positionTracker.currentPosition();
String tokenText = retrieveTokenText(c);
return tokenFactory.createToken(tokenText, currentPosition);
@ -107,7 +107,7 @@ public class LispScanner {
public ComplexTokenTextRetriever(char firstCharacter, Function<Character, Boolean> isPartOfToken) {
this.isPartOfToken = isPartOfToken;
this.text = new StringBuilder();
this.position = positionTracker.getCurrentPosition();
this.position = positionTracker.currentPosition();
this.firstCharacter = firstCharacter;
this.currentCharacter = firstCharacter;
this.previousCharacter = firstCharacter;

View File

@ -89,7 +89,7 @@ class MainTest : SymbolAndFunctionCleaner() {
}
@Test
fun runWithBadFile() {
fun `bad file displays correct error message`() {
val expectedMessage = "[critical] bad.lisp (No such file or directory)"
exit.expectSystemExitWithStatus(1)
@ -102,7 +102,7 @@ class MainTest : SymbolAndFunctionCleaner() {
}
@Test
fun runWithFile_PrintsDecoratedLastValueOnly() {
fun `interpret file prints the decorated last value only`() {
runInterpreterWithFile(FILE)
assertEquals("", systemErrLog())
@ -110,7 +110,7 @@ class MainTest : SymbolAndFunctionCleaner() {
}
@Test
fun runInteractive() {
fun `run interactive interpreter`() {
val terminal = runInterpreterAndGetInteractor()
terminal.waitForPrompt()

View File

@ -90,7 +90,7 @@ class RuntimeEnvironmentTest {
}
@Test
fun `assing a prompt decorator`() {
fun `assign a prompt decorator`() {
RuntimeEnvironment.promptDecorator = { "[$it]" }
assertThat(RuntimeEnvironment.decoratePrompt("test")).isEqualTo("[test]")

View File

@ -1,65 +0,0 @@
package file;
import org.junit.Before;
import org.junit.Test;
import java.util.Objects;
import static org.junit.Assert.assertTrue;
public class FilePositionTrackerTest {
public static final String FILE_NAME = "testFile";
private FilePositionTracker trackerUnderTest;
private FilePosition createFilePosition(int lineNumber, int columnNumber) {
FilePosition position = new FilePosition(FILE_NAME);
position.setLineNumber(lineNumber);
position.setColumnNumber(columnNumber);
return position;
}
private void assertTrackerPositionEquals(FilePosition expectedPosition) {
assertTrue(arePositionsEqual(expectedPosition, trackerUnderTest.getCurrentPosition()));
}
private boolean arePositionsEqual(FilePosition position1, FilePosition position2) {
return Objects.equals(position1.getFileName(), position2.getFileName())
&& Objects.equals(position1.getLineNumber(), position2.getLineNumber())
&& Objects.equals(position1.getColumnNumber(), position2.getColumnNumber());
}
@Before
public void setUp() {
trackerUnderTest = new FilePositionTracker(FILE_NAME);
}
@Test
public void noMovement_ReturnsInitialPosition() {
assertTrackerPositionEquals(createFilePosition(1, 0));
}
@Test
public void advanceOneColumn_ReturnsCorrectPosition() {
trackerUnderTest.incrementColumn();
assertTrackerPositionEquals(createFilePosition(1, 1));
}
@Test
public void advanceOneLine_ReturnsCorrectPosition() {
trackerUnderTest.incrementLine();
assertTrackerPositionEquals(createFilePosition(2, 0));
}
@Test
public void advanceOneLine_ResetsColumn() {
trackerUnderTest.incrementColumn();
trackerUnderTest.incrementLine();
assertTrackerPositionEquals(createFilePosition(2, 0));
}
}

View File

@ -0,0 +1,58 @@
package file
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS
@TestInstance(PER_CLASS)
class FilePositionTrackerTest {
companion object {
const val FILE_NAME = "testFile"
}
private lateinit var trackerUnderTest: FilePositionTracker
private fun createFilePosition(lineNumber: Int, columnNumber: Int): FilePosition {
return FilePosition(FILE_NAME, lineNumber, columnNumber)
}
private fun assertTrackerPositionEquals(expectedPosition: FilePosition) {
assertThat(trackerUnderTest.currentPosition()).isEqualTo(expectedPosition)
}
@BeforeEach
fun setUp() {
trackerUnderTest = FilePositionTracker(FILE_NAME)
}
@Test
fun noMovement_ReturnsInitialPosition() {
assertTrackerPositionEquals(createFilePosition(1, 0))
}
@Test
fun advanceOneColumn_ReturnsCorrectPosition() {
trackerUnderTest.incrementColumn()
assertTrackerPositionEquals(createFilePosition(1, 1))
}
@Test
fun advanceOneLine_ReturnsCorrectPosition() {
trackerUnderTest.incrementLine()
assertTrackerPositionEquals(createFilePosition(2, 0))
}
@Test
fun advanceOneLine_ResetsColumn() {
trackerUnderTest.incrementColumn()
trackerUnderTest.incrementLine()
assertTrackerPositionEquals(createFilePosition(2, 0))
}
}

View File

@ -16,52 +16,50 @@ import java.util.HashSet
class LispInterpreterTest {
private var indicatorSet: MutableSet<String>? = null
private var outputStream: ByteArrayOutputStream? = null
private var errorOutputStream: ByteArrayOutputStream? = null
private val environment: RuntimeEnvironment
private val builder: LispInterpreterBuilder
init {
this.environment = RuntimeEnvironment
this.builder = LispInterpreterBuilder
companion object {
private const val TERMINATED = "terminated"
private val FILE = LispInterpreterTest::class.java.getResource("file.lisp").file
}
private var indicatorSet = HashSet<String>()
private var outputStream = ByteArrayOutputStream()
private var errorOutputStream = ByteArrayOutputStream()
private fun setCommonFeatures() {
builder.setOutput(PrintStream(outputStream!!))
builder.setErrorOutput(PrintStream(errorOutputStream!!))
builder.setTerminationFunction { }
builder.setErrorTerminationFunction { indicatorSet!!.add(TERMINATED) }
LispInterpreterBuilder.setOutput(PrintStream(outputStream))
LispInterpreterBuilder.setErrorOutput(PrintStream(errorOutputStream))
LispInterpreterBuilder.setTerminationFunction { }
LispInterpreterBuilder.setErrorTerminationFunction { indicatorSet.add(TERMINATED) }
}
private fun assertTerminated() {
assertTrue(indicatorSet!!.contains(TERMINATED))
assertTrue(indicatorSet.contains(TERMINATED))
}
private fun assertErrorMessageWritten() {
assertTrue(errorOutputStream!!.toByteArray().size > 0)
assertTrue(errorOutputStream.toByteArray().isNotEmpty())
}
@Before
fun setUp() {
indicatorSet = HashSet()
outputStream = ByteArrayOutputStream()
errorOutputStream = ByteArrayOutputStream()
environment.reset()
builder.reset()
indicatorSet.clear()
outputStream.reset()
errorOutputStream.reset()
RuntimeEnvironment.reset()
LispInterpreterBuilder.reset()
}
@After
fun tearDown() {
environment.reset()
builder.reset()
RuntimeEnvironment.reset()
LispInterpreterBuilder.reset()
}
@Test
fun buildInteractiveInterpreter() {
setCommonFeatures()
builder.setInput(System.`in`, "stdin")
val interpreter = builder.build()
LispInterpreterBuilder.setInput(System.`in`, "stdin")
val interpreter = LispInterpreterBuilder.build()
assertTrue(interpreter is InteractiveLispInterpreter)
}
@ -69,9 +67,9 @@ class LispInterpreterTest {
@Test
fun buildNonInteractiveInterpreter() {
setCommonFeatures()
builder.setInput(System.`in`, "stdin")
builder.setNotInteractive()
val interpreter = builder.build()
LispInterpreterBuilder.setInput(System.`in`, "stdin")
LispInterpreterBuilder.setNotInteractive()
val interpreter = LispInterpreterBuilder.build()
assertFalse(interpreter is InteractiveLispInterpreter)
assertFalse(interpreter is FileLispInterpreter)
@ -80,8 +78,8 @@ class LispInterpreterTest {
@Test
fun buildFileBasedInterpreter() {
setCommonFeatures()
builder.useFile(FILE)
val interpreter = builder.build()
LispInterpreterBuilder.useFile(FILE)
val interpreter = LispInterpreterBuilder.build()
assertTrue(interpreter is FileLispInterpreter)
}
@ -89,8 +87,8 @@ class LispInterpreterTest {
@Test
fun attemptToBuildInterpreterOnBadFile() {
setCommonFeatures()
builder.useFile("does-not-exist.lisp")
builder.build()
LispInterpreterBuilder.useFile("does-not-exist.lisp")
LispInterpreterBuilder.build()
assertErrorMessageWritten()
assertTerminated()
@ -98,65 +96,59 @@ class LispInterpreterTest {
@Test
fun makeSureDecoratorsAreInitializedWithDefaults() {
builder.build()
LispInterpreterBuilder.build()
assertEquals("", environment.decoratePrompt(""))
assertEquals("", environment.decorateValueOutput(""))
assertEquals("", environment.decorateWarningOutput(""))
assertEquals("", environment.decorateErrorOutput(""))
assertEquals("", environment.decorateCriticalOutput(""))
assertEquals("", RuntimeEnvironment.decoratePrompt(""))
assertEquals("", RuntimeEnvironment.decorateValueOutput(""))
assertEquals("", RuntimeEnvironment.decorateWarningOutput(""))
assertEquals("", RuntimeEnvironment.decorateErrorOutput(""))
assertEquals("", RuntimeEnvironment.decorateCriticalOutput(""))
}
@Test
fun makeSureDecoratorsAreSetCorrectly() {
builder.setPromptDecorator { s -> "#$s#" }
builder.setValueOutputDecorator { s -> "@$s@" }
builder.setWarningOutputDecorator { s -> "%$s%" }
builder.setErrorOutputDecorator { s -> "*$s*" }
builder.setCriticalOutputDecorator { s -> "$$s$" }
builder.build()
LispInterpreterBuilder.setPromptDecorator { s -> "#$s#" }
LispInterpreterBuilder.setValueOutputDecorator { s -> "@$s@" }
LispInterpreterBuilder.setWarningOutputDecorator { s -> "%$s%" }
LispInterpreterBuilder.setErrorOutputDecorator { s -> "*$s*" }
LispInterpreterBuilder.setCriticalOutputDecorator { s -> "$$s$" }
LispInterpreterBuilder.build()
assertEquals("#x#", environment.decoratePrompt("x"))
assertEquals("@x@", environment.decorateValueOutput("x"))
assertEquals("%x%", environment.decorateWarningOutput("x"))
assertEquals("*x*", environment.decorateErrorOutput("x"))
assertEquals("\$x$", environment.decorateCriticalOutput("x"))
assertEquals("#x#", RuntimeEnvironment.decoratePrompt("x"))
assertEquals("@x@", RuntimeEnvironment.decorateValueOutput("x"))
assertEquals("%x%", RuntimeEnvironment.decorateWarningOutput("x"))
assertEquals("*x*", RuntimeEnvironment.decorateErrorOutput("x"))
assertEquals("\$x$", RuntimeEnvironment.decorateCriticalOutput("x"))
}
@Test
fun fileBasedInterpreterWorks_PrintsLastValueOnly() {
setCommonFeatures()
builder.useFile(FILE)
builder.build().interpret()
LispInterpreterBuilder.useFile(FILE)
LispInterpreterBuilder.build().interpret()
assertEquals("PICKLE\n\n", outputStream!!.toString())
assertEquals("", errorOutputStream!!.toString())
assertEquals("PICKLE\n\n", outputStream.toString())
assertEquals("", errorOutputStream.toString())
}
@Test
fun interactiveInterpreterWorks() {
setCommonFeatures()
builder.setInput(createInputStreamFromString("'pickle"), "input")
builder.build().interpret()
LispInterpreterBuilder.setInput(createInputStreamFromString("'pickle"), "input")
LispInterpreterBuilder.build().interpret()
assertEquals(format("{0}\n{1}\n{0}\n", PROMPT, "PICKLE"), outputStream!!.toString())
assertEquals("", errorOutputStream!!.toString())
assertEquals(format("{0}\n{1}\n{0}\n", PROMPT, "PICKLE"), outputStream.toString())
assertEquals("", errorOutputStream.toString())
}
@Test
fun interpreterHandlesError() {
setCommonFeatures()
builder.setNotInteractive()
builder.setInput(createInputStreamFromString("pickle"), "input")
builder.build().interpret()
LispInterpreterBuilder.setNotInteractive()
LispInterpreterBuilder.setInput(createInputStreamFromString("pickle"), "input")
LispInterpreterBuilder.build().interpret()
assertEquals("\n", outputStream!!.toString())
assertEquals("[error] symbol PICKLE has no value\n", errorOutputStream!!.toString())
}
companion object {
private val TERMINATED = "terminated"
private val FILE = LispInterpreterTest::class.java.getResource("file.lisp").file
assertEquals("\n", outputStream.toString())
assertEquals("[error] symbol PICKLE has no value\n", errorOutputStream.toString())
}
}

View File

@ -29,6 +29,5 @@ abstract class SymbolAndFunctionCleaner {
}
open fun additionalSetUp() {}
open fun additionalTearDown() {}
}

View File

@ -21,9 +21,7 @@ public class TokenFactoryTest {
@Before
public void setUp() {
tokenFactory = new TokenFactoryImpl();
testPosition = new FilePosition("testFile");
testPosition.setLineNumber(0);
testPosition.setColumnNumber(0);
testPosition = new FilePosition("testFile", 0, 0);
}
private Token createToken(String text) {