summaryrefslogtreecommitdiff
path: root/src/StringRacer.kt
diff options
context:
space:
mode:
Diffstat (limited to 'src/StringRacer.kt')
-rw-r--r--src/StringRacer.kt81
1 files changed, 81 insertions, 0 deletions
diff --git a/src/StringRacer.kt b/src/StringRacer.kt
new file mode 100644
index 0000000..d0a4a15
--- /dev/null
+++ b/src/StringRacer.kt
@@ -0,0 +1,81 @@
+package moe.nea.lisp
+
+import java.util.*
+
+class StringRacer(val filename: String, val backing: String) {
+ var idx = 0
+ val stack = Stack<Int>()
+
+ fun pushState() {
+ stack.push(idx)
+ }
+
+ fun popState() {
+ idx = stack.pop()
+ }
+
+ fun span(start: Int) = LispPosition(start, idx, filename, backing)
+
+ fun discardState() {
+ stack.pop()
+ }
+
+ fun peek(count: Int): String {
+ return backing.substring(minOf(idx, backing.length), minOf(idx + count, backing.length))
+ }
+
+ fun finished(): Boolean {
+ return peek(1).isEmpty()
+ }
+
+ fun peekReq(count: Int): String? {
+ val p = peek(count)
+ if (p.length != count)
+ return null
+ return p
+ }
+
+ fun consumeCountReq(count: Int): String? {
+ val p = peekReq(count)
+ if (p != null)
+ idx += count
+ return p
+ }
+
+ fun tryConsume(string: String): Boolean {
+ val p = peek(string.length)
+ if (p != string)
+ return false
+ idx += p.length
+ return true
+ }
+
+ fun consumeWhile(shouldConsumeThisString: (String) -> Boolean): String {
+ var lastString: String = ""
+ while (true) {
+ val nextPart = peek(1)
+ if (nextPart.isEmpty()) break
+ val nextString = lastString + nextPart
+ if (!shouldConsumeThisString(nextString)) {
+ break
+ }
+ idx++
+ lastString = nextString
+ }
+ return lastString
+ }
+
+ fun expect(search: String, errorMessage: String) {
+ if (!tryConsume(search))
+ error(errorMessage)
+ }
+
+ fun error(errorMessage: String): Nothing {
+ throw LispParsingError(backing, idx, errorMessage)
+ }
+
+ fun skipWhitespace() {
+ consumeWhile { Character.isWhitespace(it.last()) }
+ }
+}
+