--- a/progs/parser-combinators/comb1.sc Wed May 29 13:25:30 2024 +0100
+++ b/progs/parser-combinators/comb1.sc Thu Sep 19 15:47:33 2024 +0100
@@ -7,22 +7,30 @@
// Note, in the lectures I did not show the type bound
-// using is: I => Seq[_], which means that the input
-// type 'I' needs to be a sequence.
+// I : IsSeq, which means that the input type 'I' needs
+// to be a sequence that can be tested to be empty.
+
+trait IsSeq[I] {
+ extension (i: I) def isEmpty: Boolean
+}
-type IsSeq[I] = I => Seq[?]
+given IsSeq[String] = _.isEmpty
+given [I]: IsSeq[Seq[I]] = _.isEmpty
+
-abstract class Parser[I: IsSeq, T](using is: IsSeq[I]) {
+// parser class
+//==============
+
+abstract class Parser[I : IsSeq, T] {
def parse(in: I): Set[(T, I)]
def parse_all(in: I) : Set[T] =
for ((hd, tl) <- parse(in);
- if is(tl).isEmpty) yield hd
+ if tl.isEmpty) yield hd
}
-
// parser combinators
-
+//====================
// alternative parser
class AltParser[I : IsSeq, T](p: => Parser[I, T],
@@ -169,14 +177,18 @@
println(E.parse_all("1+2+3"))
-// with parser combinators (and other parsing algorithms)
-// no left-recursion is allowed, otherwise the will loop
+// with parser combinators (and many other parsing algorithms)
+// no left-recursion is allowed, otherwise the will loop;
+// newer versions of Scala (3.5) will actually give a warning
+// about this
+/*
lazy val EL: Parser[String, Int] =
((EL ~ p"+" ~ EL).map{ case ((x, y), z) => x + z} ||
(EL ~ p"*" ~ EL).map{ case ((x, y), z) => x * z} ||
(p"(" ~ EL ~ p")").map{ case ((x, y), z) => y} ||
NumParserInt)
+*/
// this will run forever:
//println(EL.parse_all("1+2+3"))