|     12 // more convenience for the map parsers later on; |     12 // more convenience for the map parsers later on; | 
|     13 // it allows writing nested patterns as |     13 // it allows writing nested patterns as | 
|     14 // case x ~ y ~ z => ... |     14 // case x ~ y ~ z => ... | 
|     15  |     15  | 
|     16  |     16  | 
|     17 case class ~[+A, +B](x: A, y: B) |     17 case class o[+A, +B](x: A, y: B) | 
|     18  |     18  | 
|     19  |     19  | 
|     20 type IsSeq[I] = I => Seq[_] |     20 type IsSeq[I] = I => Seq[?] | 
|     21  |     21  | 
|     22 abstract class Parser[I, T](using is: I => Seq[_])  { |     22 abstract class Parser[I, T](using is: I => Seq[?])  { | 
|     23   def parse(in: I): Set[(T, I)]   |     23   def parse(in: I): Set[(T, I)]   | 
|     24  |     24  | 
|     25   def parse_all(in: I) : Set[T] = |     25   def parse_all(in: I) : Set[T] = | 
|     26     for ((hd, tl) <- parse(in);  |     26     for ((hd, tl) <- parse(in);  | 
|     27         if is(tl).isEmpty) yield hd |     27         if is(tl).isEmpty) yield hd | 
|     35   def parse(in: I) = p.parse(in) ++ q.parse(in)    |     35   def parse(in: I) = p.parse(in) ++ q.parse(in)    | 
|     36 } |     36 } | 
|     37  |     37  | 
|     38 // sequence parser |     38 // sequence parser | 
|     39 class SeqParser[I : IsSeq, T, S](p: => Parser[I, T],  |     39 class SeqParser[I : IsSeq, T, S](p: => Parser[I, T],  | 
|     40                                  q: => Parser[I, S]) extends Parser[I, ~[T, S]] { |     40                                  q: => Parser[I, S]) extends Parser[I, o[T, S]] { | 
|     41   def parse(in: I) =  |     41   def parse(in: I) =  | 
|     42     for ((hd1, tl1) <- p.parse(in);  |     42     for ((hd1, tl1) <- p.parse(in);  | 
|     43          (hd2, tl2) <- q.parse(tl1)) yield (new ~(hd1, hd2), tl2) |     43          (hd2, tl2) <- q.parse(tl1)) yield (new o(hd1, hd2), tl2) | 
|     44 } |     44 } | 
|     45  |     45  | 
|     46 // map parser |     46 // map parser | 
|     47 class MapParser[I : IsSeq, T, S](p: => Parser[I, T],  |     47 class MapParser[I : IsSeq, T, S](p: => Parser[I, T],  | 
|     48                                 f: T => S) extends Parser[I, S] { |     48                                 f: T => S) extends Parser[I, S] { | 
|     85 // StrParser(_some_string_) more conveniently as  |     85 // StrParser(_some_string_) more conveniently as  | 
|     86 // |     86 // | 
|     87 // p"<_some_string_>"  |     87 // p"<_some_string_>"  | 
|     88  |     88  | 
|     89 extension (sc: StringContext)  |     89 extension (sc: StringContext)  | 
|     90   def p(args: Any*) = StrParser(sc.s(args:_*)) |     90   def p(args: Any*) = StrParser(sc.s(args*)) | 
|     91  |     91  | 
|     92  |     92  | 
|     93 // more convenient syntax for parser combinators |     93 // more convenient syntax for parser combinators | 
|     94 extension [I : IsSeq, T](p: Parser[I, T]) { |     94 extension [I : IsSeq, T](p: Parser[I, T]) { | 
|     95   def ||(q : => Parser[I, T]) = new AltParser[I, T](p, q) |     95   def ||(q : => Parser[I, T]) = new AltParser[I, T](p, q) | 
|     96   def ~[S] (q : => Parser[I, S]) = new SeqParser[I, T, S](p, q) |     96   def o[S] (q : => Parser[I, S]) = new SeqParser[I, T, S](p, q) | 
|     97   def map[S](f: => T => S) = new MapParser[I, T, S](p, f) |     97   def map[S](f: => T => S) = new MapParser[I, T, S](p, f) | 
|     98 } |     98 } | 
|     99  |     99  | 
|    100  |    100  | 
|    101 // the abstract syntax trees for the WHILE language |    101 // the abstract syntax trees for the WHILE language | 
|    122 case class Or(b1: BExp, b2: BExp) extends BExp |    122 case class Or(b1: BExp, b2: BExp) extends BExp | 
|    123  |    123  | 
|    124  |    124  | 
|    125 // arithmetic expressions |    125 // arithmetic expressions | 
|    126 lazy val AExp: Parser[String, AExp] =  |    126 lazy val AExp: Parser[String, AExp] =  | 
|    127   (Te ~ p"+" ~ AExp).map[AExp]{ case x ~ _ ~ z => Aop("+", x, z) } || |    127   (Te o p"+" o AExp).map[AExp]{ case x o _ o z => Aop("+", x, z): AExp } || | 
|    128   (Te ~ p"-" ~ AExp).map[AExp]{ case x ~ _ ~ z => Aop("-", x, z) } || Te |    128   (Te o p"-" o AExp).map[AExp]{ case x o _ o z => Aop("-", x, z) } || Te | 
|    129 lazy val Te: Parser[String, AExp] =  |    129 lazy val Te: Parser[String, AExp] =  | 
|    130   (Fa ~ p"*" ~ Te).map[AExp]{ case x ~ _ ~ z => Aop("*", x, z) } ||  |    130   (Fa o p"*" o Te).map[AExp]{ case x o _ o z => Aop("*", x, z) } ||  | 
|    131   (Fa ~ p"/" ~ Te).map[AExp]{ case x ~ _ ~ z => Aop("/", x, z) } || Fa   |    131   (Fa o p"/" o Te).map[AExp]{ case x o _ o z => Aop("/", x, z) } || Fa   | 
|    132 lazy val Fa: Parser[String, AExp] =  |    132 lazy val Fa: Parser[String, AExp] =  | 
|    133    (p"(" ~ AExp ~ p")").map{ case _ ~ y ~ _ => y } ||  |    133    (p"(" o AExp o p")").map{ case _ o y o _ => y } ||  | 
|    134    IdParser.map(Var(_)) ||  |    134    IdParser.map(Var(_)) ||  | 
|    135    NumParser.map(Num(_)) |    135    NumParser.map(Num(_)) | 
|    136  |    136  | 
|    137 // boolean expressions with some simple nesting |    137 // boolean expressions with some simple nesting | 
|    138 lazy val BExp: Parser[String, BExp] =  |    138 lazy val BExp: Parser[String, BExp] =  |