diff -r c7009356ddd8 -r c0600f8b6427 progs/parser-combinators/comb1.sc --- 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"))