Skip to content

Commit

Permalink
[prelude] Parse effect (#792)
Browse files Browse the repository at this point in the history
Provides parsing capabilities with backtracking and lookahead support.
The effect assumes there's an input string in scope (`Var`) being parsed
and operations consume from it, evaluating multiple possible branches
with `Choice` and failing with `Abort` if necessary. It's also possible
to mix other effects with `Parse`.
  • Loading branch information
fwbrasil authored Oct 30, 2024
1 parent 284fdb1 commit 579a989
Show file tree
Hide file tree
Showing 8 changed files with 1,110 additions and 5 deletions.
2 changes: 2 additions & 0 deletions kyo-data/shared/src/main/scala/kyo/Tag.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ object Tag:

inline given apply[A]: Tag[A] = ${ TagMacro.tagImpl[A] }

private[kyo] def fromRaw[A](tag: String): Tag[A] = tag

extension [A](t1: Tag[A])

inline def erased: Tag[Any] = t1.asInstanceOf[Tag[Any]]
Expand Down
13 changes: 13 additions & 0 deletions kyo-data/shared/src/main/scala/kyo/Text.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ opaque type Text >: String = String | Op

object Text:

given Tag[Text] = Tag.fromRaw("kyo.Text")

def apply(s: String): Text = s

def empty: Text = ""
Expand Down Expand Up @@ -230,6 +232,17 @@ object Text:

def compact: Text = self.toString()

def is(other: Text): Boolean =
if self.length != other.length then false
else
@tailrec
def loop(i: Int): Boolean =
if i >= self.length then true
else if self.charAt(i) != other.charAt(i) then false
else loop(i + 1)
loop(0)
end is

end extension

private[kyo] object internal:
Expand Down
45 changes: 45 additions & 0 deletions kyo-data/shared/src/test/scala/kyo/TextTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -569,4 +569,49 @@ class TextTest extends Test:
}
}

"is (equality)" - {
"simple texts" in {
assert(Text("hello").is(Text("hello")))
assert(!Text("hello").is(Text("world")))
}

"empty texts" in {
assert(Text("").is(Text("")))
assert(!Text("").is(Text("a")))
}

"case sensitivity" in {
assert(!Text("Hello").is(Text("hello")))
}

"concatenated texts" in {
assert((Text("hello") + " world").is(Text("hello world")))
assert(!(Text("hello") + "world").is(Text("helloworld ")))
}

"cut texts" in {
assert(Text("hello world").substring(0, 5).is(Text("hello")))
assert(!Text("hello world").substring(0, 5).is(Text("world")))
}

"mixed operations" in {
val text1 = Text("hello") + " " + "world"
val text2 = Text("hello world").substring(0, 11)
assert(text1.is(text2))
}

"unicode support" in {
assert(Text("Hello 🌍").is(Text("Hello 🌍")))
assert(!Text("Hello 🌍").is(Text("Hello 🌎")))
}

"large texts" in {
val large1 = Text("a" * 1000000)
val large2 = Text("a" * 1000000)
val large3 = Text("a" * 999999 + "b")
assert(large1.is(large2))
assert(!large1.is(large3))
}
}

end TextTest
Loading

0 comments on commit 579a989

Please sign in to comment.