expression parsing, sorted list, tree, other shit; bump to 0.10
This commit is contained in:
@@ -4,7 +4,6 @@ import blitz.collections.inBounds
|
||||
import blitz.str.ColoredChar
|
||||
import blitz.str.MutMultiColoredMultiLineString
|
||||
import blitz.str.MutMultiLineString
|
||||
import blitz.str.MutString
|
||||
import blitz.term.AnsiiMode
|
||||
import blitz.term.Terminal
|
||||
|
||||
@@ -143,7 +142,7 @@ object Errors {
|
||||
|
||||
byCol.filter { it.isLongDesc }.forEach {
|
||||
val msgLines = MutMultiLineString.from(it.message, fill = ' ')
|
||||
msg.set(row, nextCol, msgLines, Terminal.COLORS.WHITE.brighter.fg)
|
||||
msg[row, nextCol, msgLines] = Terminal.COLORS.WHITE.brighter.fg
|
||||
row ++
|
||||
}
|
||||
|
||||
@@ -153,41 +152,4 @@ object Errors {
|
||||
Terminal.errln("================================================================================", config.styles[worst]!! + Terminal.STYLES.BOLD)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val source = Errors.Source("main.kt", MutMultiLineString.from("""
|
||||
fn main() {
|
||||
return 1 + 0
|
||||
}
|
||||
""".trimIndent(), ' '))
|
||||
|
||||
val errors = listOf(
|
||||
Errors.Error(
|
||||
"cannot return integer from function with return type void",
|
||||
Errors.Error.Level.ERROR,
|
||||
Errors.Location(source, 1, 11, 5)
|
||||
),
|
||||
Errors.Error(
|
||||
"return is deprecated. use yeet instead",
|
||||
Errors.Error.Level.WARN,
|
||||
Errors.Location(source, 1, 4, 6)
|
||||
),
|
||||
Errors.Error(
|
||||
"useless addition",
|
||||
Errors.Error.Level.INFO,
|
||||
Errors.Location(source, 1, 13, 3),
|
||||
isHint = true
|
||||
),
|
||||
Errors.Error(
|
||||
"Visit https://www.example.com/doc/yeet for more information",
|
||||
Errors.Error.Level.INFO,
|
||||
Errors.Location(source, 1, 0, 0),
|
||||
isLongDesc = true
|
||||
)
|
||||
)
|
||||
|
||||
val config = Errors.PrintConfig()
|
||||
|
||||
Errors.print(config, errors)
|
||||
}
|
@@ -7,12 +7,4 @@ fun ByteBatchSequence.stringify(batch: Int = 64): Sequence<String> {
|
||||
iter.nextBytes(batch).decodeToString()
|
||||
else null
|
||||
}
|
||||
}
|
||||
|
||||
fun Sequence<String>.flatten(): String {
|
||||
val out = StringBuilder()
|
||||
forEach {
|
||||
out.append(it)
|
||||
}
|
||||
return out.toString()
|
||||
}
|
4
src/main/kotlin/blitz/collections/Constructors.kt
Normal file
4
src/main/kotlin/blitz/collections/Constructors.kt
Normal file
@@ -0,0 +1,4 @@
|
||||
package blitz.collections
|
||||
|
||||
fun <T, C: Comparable<C>> SortedArrayList(sorter: (T) -> C) =
|
||||
SortedList(ArrayList(), sorter)
|
@@ -7,4 +7,47 @@ fun <T, R> Iterator<T>.mapModifier(fn: (T) -> R): Iterator<R> =
|
||||
|
||||
override fun hasNext(): Boolean =
|
||||
this@mapModifier.hasNext()
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> generateIterator(fn: () -> T?): Iterator<T> =
|
||||
object: Iterator<T> {
|
||||
var calc = false
|
||||
var nx: T? = null
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
if (!calc) {
|
||||
nx = fn()
|
||||
calc = true
|
||||
}
|
||||
return nx != null
|
||||
}
|
||||
|
||||
override fun next(): T {
|
||||
if (!hasNext())
|
||||
throw Exception("iterator end")
|
||||
calc = false
|
||||
return nx!!
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Can't explain this function. Look at the source of [blitz.parse.tokenize] as an example
|
||||
*/
|
||||
fun <T, R> Iterator<T>.funnyMap(fn: (UnGettableIterator<T>) -> R?): Iterator<R> {
|
||||
val iter = asUnGettable()
|
||||
return generateIterator { fn(iter) }
|
||||
}
|
||||
|
||||
fun <T> Iterator<T>.collect(to: MutableList<T> = mutableListOf()): MutableList<T> {
|
||||
forEachRemaining {
|
||||
to.add(it)
|
||||
}
|
||||
return to
|
||||
}
|
||||
|
||||
fun <T> Iterator<T>.collect(to: Vec<T>): Vec<T> {
|
||||
forEachRemaining {
|
||||
to.pushBack(it)
|
||||
}
|
||||
return to
|
||||
}
|
7
src/main/kotlin/blitz/collections/MapEmpty.kt
Normal file
7
src/main/kotlin/blitz/collections/MapEmpty.kt
Normal file
@@ -0,0 +1,7 @@
|
||||
package blitz.collections
|
||||
|
||||
fun <T> Collection<T>.nullIfEmpty(): Collection<T>? =
|
||||
ifEmpty { null }
|
||||
|
||||
fun String.nullIfEmpty(): String? =
|
||||
ifEmpty { null }
|
53
src/main/kotlin/blitz/collections/Search.kt
Normal file
53
src/main/kotlin/blitz/collections/Search.kt
Normal file
@@ -0,0 +1,53 @@
|
||||
package blitz.collections
|
||||
|
||||
import kotlin.math.max
|
||||
|
||||
object Search {
|
||||
/**
|
||||
* Find a element by comparing.
|
||||
* Only works on sorted lists
|
||||
*/
|
||||
fun <T, C: Comparable<C>> findElementComparing(
|
||||
list: List<T>,
|
||||
element: T,
|
||||
comparer: (T) -> C,
|
||||
): Int {
|
||||
var rev = max(0, list.size / 2 - 1)
|
||||
var prev = 0
|
||||
|
||||
while (true) {
|
||||
// outside of array:
|
||||
if (rev < 0)
|
||||
break
|
||||
|
||||
// outside of array:
|
||||
if (rev >= list.size)
|
||||
break
|
||||
|
||||
val cmp = comparer(element)
|
||||
.compareTo(comparer(list[rev]))
|
||||
|
||||
// found:
|
||||
if (cmp == 0)
|
||||
return rev
|
||||
|
||||
// in between of two existing values:
|
||||
if (cmp > 0 && prev < 0)
|
||||
break
|
||||
|
||||
// in between of two existing values:
|
||||
if (cmp < 0 && prev > 0)
|
||||
break
|
||||
|
||||
if (cmp < 0)
|
||||
rev --
|
||||
|
||||
else if (cmp > 0)
|
||||
rev ++
|
||||
|
||||
prev = cmp
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
}
|
@@ -4,6 +4,7 @@ interface IndexableSequence<T>: Sequence<T> {
|
||||
operator fun get(index: Int): T
|
||||
}
|
||||
|
||||
// TODO: rename to map
|
||||
fun <T> IndexableSequence<T>.modifier(mod: (Sequence<T>) -> Sequence<T>) =
|
||||
object : IndexableSequence<T> {
|
||||
val other = mod(this@modifier)
|
||||
|
128
src/main/kotlin/blitz/collections/SortedList.kt
Normal file
128
src/main/kotlin/blitz/collections/SortedList.kt
Normal file
@@ -0,0 +1,128 @@
|
||||
package blitz.collections
|
||||
|
||||
import kotlin.math.max
|
||||
|
||||
/**
|
||||
* A mutable list that uses a different mutable list as underlying data structure.
|
||||
* The list guarantees all elements to stay sorted unless manually inserted.
|
||||
*/
|
||||
class SortedList<T, C: Comparable<C>>(
|
||||
private val al: MutableList<T>,
|
||||
private val sorter: (T) -> C
|
||||
): MutableList<T>, RandomAccess {
|
||||
override val size: Int =
|
||||
al.size
|
||||
|
||||
override fun clear() =
|
||||
al.clear()
|
||||
|
||||
override fun addAll(elements: Collection<T>): Boolean {
|
||||
elements.forEach(::add)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun addAll(index: Int, elements: Collection<T>): Boolean =
|
||||
al.addAll(index, elements)
|
||||
|
||||
override fun add(index: Int, element: T) =
|
||||
al.add(index, element)
|
||||
|
||||
override fun add(element: T): Boolean {
|
||||
var rev = max(0, al.size / 2 - 1)
|
||||
var prev = 0
|
||||
while (true) {
|
||||
if (rev < 0) {
|
||||
al.add(0, element)
|
||||
return true
|
||||
}
|
||||
if (rev >= al.size) {
|
||||
al.add(element)
|
||||
return true
|
||||
}
|
||||
val cmp = sorter(element)
|
||||
.compareTo(sorter(al[rev]))
|
||||
if (cmp == 0) {
|
||||
al.add(rev, element)
|
||||
return true
|
||||
}
|
||||
if (cmp > 0 && prev < 0) {
|
||||
al.add(rev - 1, element)
|
||||
return true
|
||||
}
|
||||
if (cmp < 0 && prev > 0) {
|
||||
al.add(rev, element)
|
||||
return true
|
||||
}
|
||||
if (cmp < 0)
|
||||
rev --
|
||||
else if (cmp > 0)
|
||||
rev ++
|
||||
prev = cmp
|
||||
}
|
||||
}
|
||||
|
||||
override fun get(index: Int): T =
|
||||
al[index]
|
||||
|
||||
override fun isEmpty(): Boolean =
|
||||
al.isEmpty()
|
||||
|
||||
override fun iterator(): MutableIterator<T> =
|
||||
al.iterator()
|
||||
|
||||
override fun listIterator(): MutableListIterator<T> =
|
||||
al.listIterator()
|
||||
|
||||
override fun listIterator(index: Int): MutableListIterator<T> =
|
||||
al.listIterator(index)
|
||||
|
||||
override fun removeAt(index: Int): T =
|
||||
al.removeAt(index)
|
||||
|
||||
override fun subList(fromIndex: Int, toIndex: Int): MutableList<T> =
|
||||
al.subList(fromIndex, toIndex)
|
||||
|
||||
override fun set(index: Int, element: T): T =
|
||||
al.set(index, element)
|
||||
|
||||
override fun retainAll(elements: Collection<T>): Boolean =
|
||||
al.retainAll(elements)
|
||||
|
||||
override fun removeAll(elements: Collection<T>): Boolean {
|
||||
var rem = false
|
||||
for (x in elements) {
|
||||
if (remove(x))
|
||||
rem = true
|
||||
}
|
||||
return rem
|
||||
}
|
||||
|
||||
override fun remove(element: T): Boolean {
|
||||
val i = Search.findElementComparing(al, element, sorter)
|
||||
if (i == -1)
|
||||
return false
|
||||
removeAt(i)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun lastIndexOf(element: T): Int =
|
||||
al.lastIndexOf(element)
|
||||
|
||||
override fun indexOf(element: T): Int =
|
||||
al.indexOf(element)
|
||||
|
||||
override fun containsAll(elements: Collection<T>): Boolean =
|
||||
elements.all { contains(it) }
|
||||
|
||||
override fun contains(element: T): Boolean =
|
||||
Search.findElementComparing(al, element, sorter) != -1
|
||||
|
||||
override fun toString(): String =
|
||||
al.toString()
|
||||
|
||||
inline fun sorted(): SortedList<T, C> =
|
||||
this
|
||||
|
||||
inline fun sortedDescending(): List<T> =
|
||||
this.reversed()
|
||||
}
|
79
src/main/kotlin/blitz/collections/SynchronizedList.kt
Normal file
79
src/main/kotlin/blitz/collections/SynchronizedList.kt
Normal file
@@ -0,0 +1,79 @@
|
||||
package blitz.collections
|
||||
|
||||
import blitz.async.Lock
|
||||
|
||||
/**
|
||||
* Wraps any MutableList.
|
||||
* Concurrent by synchronizing.
|
||||
*/
|
||||
class SynchronizedList<T, L: MutableList<T>>(
|
||||
private val innerList: L
|
||||
): MutableList<T>, RandomAccess {
|
||||
private val innerLock = Lock()
|
||||
|
||||
fun <R> access(block: (L) -> R): R =
|
||||
innerLock.use { block(innerList) }
|
||||
|
||||
override val size: Int
|
||||
get() = innerList.size
|
||||
|
||||
override fun clear() =
|
||||
access { it.clear() }
|
||||
|
||||
override fun addAll(elements: Collection<T>): Boolean =
|
||||
access { it.addAll(elements) }
|
||||
|
||||
override fun addAll(index: Int, elements: Collection<T>): Boolean =
|
||||
access { it.addAll(index, elements) }
|
||||
|
||||
override fun add(index: Int, element: T) =
|
||||
access { it.add(index, element) }
|
||||
|
||||
override fun add(element: T): Boolean =
|
||||
access { it.add(element) }
|
||||
|
||||
override fun get(index: Int): T =
|
||||
access { it.get(index) }
|
||||
|
||||
override fun isEmpty(): Boolean =
|
||||
access { it.isEmpty() }
|
||||
|
||||
override fun iterator(): MutableIterator<T> =
|
||||
access { it.iterator() }
|
||||
|
||||
override fun listIterator(): MutableListIterator<T> =
|
||||
access { it.listIterator() }
|
||||
|
||||
override fun listIterator(index: Int): MutableListIterator<T> =
|
||||
access { it.listIterator(index) }
|
||||
|
||||
override fun removeAt(index: Int): T =
|
||||
access { it.removeAt(index) }
|
||||
|
||||
override fun subList(fromIndex: Int, toIndex: Int): MutableList<T> =
|
||||
access { it.subList(fromIndex, toIndex) }
|
||||
|
||||
override fun set(index: Int, element: T): T =
|
||||
access { it.set(index, element) }
|
||||
|
||||
override fun retainAll(elements: Collection<T>): Boolean =
|
||||
access { it.retainAll(elements) }
|
||||
|
||||
override fun removeAll(elements: Collection<T>): Boolean =
|
||||
access { it.removeAll(elements) }
|
||||
|
||||
override fun remove(element: T): Boolean =
|
||||
access { it.remove(element) }
|
||||
|
||||
override fun lastIndexOf(element: T): Int =
|
||||
access { it.lastIndexOf(element) }
|
||||
|
||||
override fun indexOf(element: T): Int =
|
||||
access { it.indexOf(element) }
|
||||
|
||||
override fun containsAll(elements: Collection<T>): Boolean =
|
||||
access { it.containsAll(elements) }
|
||||
|
||||
override fun contains(element: T): Boolean =
|
||||
access { it.contains(element) }
|
||||
}
|
84
src/main/kotlin/blitz/collections/Tree.kt
Normal file
84
src/main/kotlin/blitz/collections/Tree.kt
Normal file
@@ -0,0 +1,84 @@
|
||||
package blitz.collections
|
||||
|
||||
class Tree<T> {
|
||||
var root: Node<T>? = null
|
||||
|
||||
operator fun plusAssign(value: T) {
|
||||
val node = Node<T>()
|
||||
node.value = value
|
||||
root?.children?.add(node)
|
||||
}
|
||||
|
||||
fun traverse(traverser: TreeTraverser<T>) =
|
||||
root?.traverse(traverser)
|
||||
|
||||
fun traverse(process: (Node<T>) -> Boolean) =
|
||||
root?.traverse(process)
|
||||
|
||||
fun updateParents() {
|
||||
traverse { node ->
|
||||
node.children.forEach { it.parent = node }
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return root.toString()
|
||||
}
|
||||
}
|
||||
|
||||
class Node<T>(
|
||||
var value: T? = null,
|
||||
var children: MutableList<Node<T>> = mutableListOf()
|
||||
) {
|
||||
var parent: Node<T>? = null
|
||||
|
||||
fun traverse(traverser: TreeTraverser<T>) =
|
||||
traverser.traverse(this)
|
||||
|
||||
fun traverse(process: (Node<T>) -> Boolean) {
|
||||
val trav = object : TreeTraverser<T> {
|
||||
override fun process(node: Node<T>): Boolean {
|
||||
return process(node)
|
||||
}
|
||||
}
|
||||
traverse(trav)
|
||||
}
|
||||
|
||||
operator fun plusAssign(value: T) {
|
||||
val node = Node<T>()
|
||||
node.value = value
|
||||
children.add(node)
|
||||
}
|
||||
|
||||
fun toLines(): List<Pair<Int, String>> {
|
||||
val lines = mutableListOf<Pair<Int, String>>()
|
||||
lines += 0 to value.toString()
|
||||
children.forEach { child ->
|
||||
child.toLines().forEach { (indent, line) ->
|
||||
lines += indent + 1 to line
|
||||
}
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val lines = toLines()
|
||||
val sb = StringBuilder()
|
||||
lines.forEach { (indent, line) ->
|
||||
sb.append(" ".repeat(indent * 2))
|
||||
sb.append(line)
|
||||
sb.append("\n")
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
}
|
||||
|
||||
interface TreeTraverser<T> {
|
||||
fun process(node: Node<T>): Boolean /* true if continue, false if stop */
|
||||
|
||||
fun traverse(tree: Node<T>) {
|
||||
if (!process(tree)) return
|
||||
tree.children.forEach { traverse(it) }
|
||||
}
|
||||
}
|
27
src/main/kotlin/blitz/collections/Ungettable.kt
Normal file
27
src/main/kotlin/blitz/collections/Ungettable.kt
Normal file
@@ -0,0 +1,27 @@
|
||||
package blitz.collections
|
||||
|
||||
interface UnGettableIterator<T>: Iterator<T> {
|
||||
/**
|
||||
* Undo the previous next() operation. Only possible once per next()!
|
||||
*/
|
||||
fun unGet()
|
||||
}
|
||||
|
||||
fun <T> Iterator<T>.asUnGettable(): UnGettableIterator<T> =
|
||||
object: UnGettableIterator<T> {
|
||||
private var prev: T? = null
|
||||
private var unget = false
|
||||
|
||||
override fun unGet() {
|
||||
if (prev == null)
|
||||
throw Exception("Cannot unGet because there was no previous")
|
||||
unget = true
|
||||
}
|
||||
|
||||
override fun hasNext(): Boolean =
|
||||
unget || this@asUnGettable.hasNext()
|
||||
|
||||
override fun next(): T =
|
||||
if (unget) prev!!.also { unget = false }
|
||||
else this@asUnGettable.next().also { prev = it }
|
||||
}
|
20
src/main/kotlin/blitz/ice/Cooled.kt
Normal file
20
src/main/kotlin/blitz/ice/Cooled.kt
Normal file
@@ -0,0 +1,20 @@
|
||||
package blitz.ice
|
||||
|
||||
class Cooled<T>(private val of: T): Freezable {
|
||||
private var frozen = false
|
||||
|
||||
override fun freeze() {
|
||||
frozen = true
|
||||
}
|
||||
|
||||
override fun isFrozen(): Boolean {
|
||||
return frozen
|
||||
}
|
||||
|
||||
fun getOrNull(): T? =
|
||||
if (isFrozen()) null else of
|
||||
|
||||
fun <R> use(block: (T) -> R): R? =
|
||||
if (isFrozen()) null
|
||||
else block(of)
|
||||
}
|
10
src/main/kotlin/blitz/ice/Freezable.kt
Normal file
10
src/main/kotlin/blitz/ice/Freezable.kt
Normal file
@@ -0,0 +1,10 @@
|
||||
package blitz.ice
|
||||
|
||||
interface Freezable {
|
||||
fun freeze()
|
||||
fun isFrozen(): Boolean
|
||||
}
|
||||
|
||||
inline fun <R> Freezable.map(block: (Freezable) -> R): R? =
|
||||
if (isFrozen()) null
|
||||
else block(this)
|
36
src/main/kotlin/blitz/logic/Bools.kt
Normal file
36
src/main/kotlin/blitz/logic/Bools.kt
Normal file
@@ -0,0 +1,36 @@
|
||||
package blitz.logic
|
||||
|
||||
/**
|
||||
* Execute a block if the boolean is true.
|
||||
*/
|
||||
fun Boolean.then(block: () -> Unit): Boolean {
|
||||
if (this) {
|
||||
block()
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a block if the boolean is false.
|
||||
*/
|
||||
fun Boolean.otherwise(block: () -> Unit): Boolean {
|
||||
if (!this) {
|
||||
block()
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a block if the boolean is true, otherwise execute another block.
|
||||
*/
|
||||
fun Boolean.then(block: () -> Unit, otherwise: () -> Unit): Boolean {
|
||||
if (this) {
|
||||
block()
|
||||
} else {
|
||||
otherwise()
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
7
src/main/kotlin/blitz/parse/Operator.kt
Normal file
7
src/main/kotlin/blitz/parse/Operator.kt
Normal file
@@ -0,0 +1,7 @@
|
||||
package blitz.parse
|
||||
|
||||
data class Operator(
|
||||
val symbol: Char,
|
||||
val precedence: Int = 0,
|
||||
val leftAssociative: Boolean = true,
|
||||
)
|
62
src/main/kotlin/blitz/parse/ShuntingYard.kt
Normal file
62
src/main/kotlin/blitz/parse/ShuntingYard.kt
Normal file
@@ -0,0 +1,62 @@
|
||||
package blitz.parse
|
||||
|
||||
fun Iterator<Token>.shuntingYard(): Iterator<Token> {
|
||||
val iter = this
|
||||
val opStack = mutableListOf<Token>()
|
||||
return sequence {
|
||||
while (iter.hasNext()) {
|
||||
val tk0 = iter.next()
|
||||
when (tk0.type) {
|
||||
Token.Type.NUMBER -> yield(tk0)
|
||||
Token.Type.IDENT -> opStack.add(tk0)
|
||||
Token.Type.OPERATOR -> {
|
||||
while (true) {
|
||||
if (opStack.isEmpty())
|
||||
break
|
||||
val oo = opStack.last()
|
||||
if (oo.type == Token.Type.PAREN_OPEN)
|
||||
break
|
||||
if (!((oo.op!!.precedence > tk0.op!!.precedence) || (tk0.op.precedence == oo.op.precedence && tk0.op.leftAssociative)))
|
||||
break
|
||||
opStack.removeLast()
|
||||
yield(oo)
|
||||
}
|
||||
opStack.add(tk0)
|
||||
}
|
||||
Token.Type.COMMA -> {
|
||||
while (true) {
|
||||
if (opStack.isEmpty())
|
||||
break
|
||||
val oo = opStack.last()
|
||||
if (oo.type == Token.Type.PAREN_OPEN)
|
||||
break
|
||||
opStack.removeLast()
|
||||
}
|
||||
}
|
||||
Token.Type.PAREN_OPEN -> opStack.add(tk0)
|
||||
Token.Type.PAREN_CLOSE -> {
|
||||
while (true) {
|
||||
if (opStack.isEmpty())
|
||||
throw Exception("Unexpected closing parenthesis!")
|
||||
val oo = opStack.last()
|
||||
if (oo.type == Token.Type.PAREN_OPEN)
|
||||
break
|
||||
opStack.removeLast()
|
||||
yield(oo)
|
||||
}
|
||||
if (opStack.removeLastOrNull()?.type != Token.Type.PAREN_OPEN)
|
||||
throw Exception("Unexpected closing parenthesis!")
|
||||
if (opStack.lastOrNull()?.type == Token.Type.IDENT)
|
||||
yield(opStack.removeLast())
|
||||
}
|
||||
Token.Type.SEPARATOR -> continue
|
||||
}
|
||||
}
|
||||
while (opStack.isNotEmpty()) {
|
||||
val oo = opStack.removeLast()
|
||||
if (oo.type in listOf(Token.Type.PAREN_OPEN, Token.Type.PAREN_CLOSE))
|
||||
throw Exception("Mismatched parenthesis")
|
||||
yield(oo)
|
||||
}
|
||||
}.iterator()
|
||||
}
|
17
src/main/kotlin/blitz/parse/Token.kt
Normal file
17
src/main/kotlin/blitz/parse/Token.kt
Normal file
@@ -0,0 +1,17 @@
|
||||
package blitz.parse
|
||||
|
||||
data class Token(
|
||||
val type: Type,
|
||||
val value: String? = null,
|
||||
val op: Operator? = null,
|
||||
) {
|
||||
enum class Type {
|
||||
IDENT,
|
||||
NUMBER,
|
||||
PAREN_OPEN,
|
||||
PAREN_CLOSE,
|
||||
OPERATOR,
|
||||
SEPARATOR,
|
||||
COMMA,
|
||||
}
|
||||
}
|
91
src/main/kotlin/blitz/parse/Tokenize.kt
Normal file
91
src/main/kotlin/blitz/parse/Tokenize.kt
Normal file
@@ -0,0 +1,91 @@
|
||||
package blitz.parse
|
||||
|
||||
import blitz.collections.funnyMap
|
||||
|
||||
fun Iterator<Char>.tokenize(
|
||||
operators: Collection<Operator> = emptyList(),
|
||||
ignore: Collection<Char> = emptyList(),
|
||||
): Iterator<Token> =
|
||||
funnyMap {
|
||||
val builder = StringBuilder()
|
||||
var ident = false
|
||||
var num = false
|
||||
var paren: Char? = null
|
||||
var op: Operator? = null
|
||||
var sep = false
|
||||
var comma = false
|
||||
while (it.hasNext()) {
|
||||
when (val c = it.next()) {
|
||||
in 'a'..'z',
|
||||
in 'A'..'Z',
|
||||
'_' -> {
|
||||
if (num) {
|
||||
it.unGet()
|
||||
break
|
||||
} else {
|
||||
builder.append(c)
|
||||
ident = true
|
||||
}
|
||||
}
|
||||
in '0'..'9' -> {
|
||||
builder.append(c)
|
||||
if (!ident)
|
||||
num = true
|
||||
}
|
||||
'.' -> {
|
||||
if (num)
|
||||
builder.append(it)
|
||||
else {
|
||||
it.unGet()
|
||||
break
|
||||
}
|
||||
}
|
||||
'(',
|
||||
')' -> {
|
||||
if (!ident && !num)
|
||||
paren = c
|
||||
else
|
||||
it.unGet()
|
||||
break
|
||||
}
|
||||
in ignore -> {
|
||||
if (!ident && !num)
|
||||
sep = true
|
||||
else
|
||||
it.unGet()
|
||||
break
|
||||
}
|
||||
',' -> {
|
||||
if (!ident && !num)
|
||||
comma = true
|
||||
else
|
||||
it.unGet()
|
||||
break
|
||||
}
|
||||
else -> {
|
||||
val oo = operators.firstOrNull { o -> o.symbol == c }
|
||||
if (oo != null)
|
||||
op = oo
|
||||
else
|
||||
it.unGet()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ident)
|
||||
Token(Token.Type.IDENT, builder.toString())
|
||||
else if (num)
|
||||
Token(Token.Type.NUMBER, builder.toString())
|
||||
else if (paren == '(')
|
||||
Token(Token.Type.PAREN_OPEN)
|
||||
else if (paren == ')')
|
||||
Token(Token.Type.PAREN_CLOSE)
|
||||
else if (op != null)
|
||||
Token(Token.Type.OPERATOR, op = op)
|
||||
else if (sep)
|
||||
Token(Token.Type.SEPARATOR)
|
||||
else if (comma)
|
||||
Token(Token.Type.COMMA)
|
||||
else
|
||||
null
|
||||
}
|
25
src/main/kotlin/blitz/str/Flatten.kt
Normal file
25
src/main/kotlin/blitz/str/Flatten.kt
Normal file
@@ -0,0 +1,25 @@
|
||||
package blitz.str
|
||||
|
||||
fun Sequence<String>.flattenToString(): String {
|
||||
val out = StringBuilder()
|
||||
forEach {
|
||||
out.append(it)
|
||||
}
|
||||
return out.toString()
|
||||
}
|
||||
|
||||
fun Iterable<String>.flattenToString(): String {
|
||||
val out = StringBuilder()
|
||||
forEach {
|
||||
out.append(it)
|
||||
}
|
||||
return out.toString()
|
||||
}
|
||||
|
||||
fun Iterator<Char>.collectToString(): String {
|
||||
val out = StringBuilder()
|
||||
forEachRemaining {
|
||||
out.append(it)
|
||||
}
|
||||
return out.toString()
|
||||
}
|
Reference in New Issue
Block a user