diff -r 15973df32613 -r 2bf1516d730f progs/parser-combinators/comb2.sc --- a/progs/parser-combinators/comb2.sc Wed Dec 21 14:33:05 2022 +0000 +++ b/progs/parser-combinators/comb2.sc Tue Apr 04 22:31:09 2023 +0100 @@ -18,37 +18,33 @@ case class ~[+A, +B](x: A, y: B) -// constraint for the input -type IsSeq[A] = A => Seq[_] - - -abstract class Parser[I : IsSeq, T]{ - def parse(in: I): Set[(T, I)] +abstract class Parser[I, T](using is: I => Seq[_]) { + def parse(in: I): Set[(T, I)] def parse_all(in: I) : Set[T] = for ((hd, tl) <- parse(in); - if tl.isEmpty) yield hd + if is(tl).isEmpty) yield hd } // parser combinators +// alternative parser +class AltParser[I, T](p: => Parser[I, T], + q: => Parser[I, T])(using I => Seq[_]) extends Parser[I, T] { + def parse(in: I) = p.parse(in) ++ q.parse(in) +} + // sequence parser -class SeqParser[I : IsSeq, T, S](p: => Parser[I, T], - q: => Parser[I, S]) extends Parser[I, ~[T, S]] { +class SeqParser[I, T, S](p: => Parser[I, T], + q: => Parser[I, S])(using I => Seq[_]) extends Parser[I, ~[T, S]] { def parse(in: I) = for ((hd1, tl1) <- p.parse(in); (hd2, tl2) <- q.parse(tl1)) yield (new ~(hd1, hd2), tl2) } -// alternative parser -class AltParser[I : IsSeq, T](p: => Parser[I, T], - q: => Parser[I, T]) extends Parser[I, T] { - def parse(in: I) = p.parse(in) ++ q.parse(in) -} - // map parser -class MapParser[I : IsSeq, T, S](p: => Parser[I, T], - f: T => S) extends Parser[I, S] { +class MapParser[I, T, S](p: => Parser[I, T], + f: T => S)(using I => Seq[_]) extends Parser[I, S] { def parse(in: I) = for ((hd, tl) <- p.parse(in)) yield (f(hd), tl) } @@ -89,19 +85,20 @@ // // p"<_some_string_>" -implicit def parser_interpolation(sc: StringContext) = new { - def p(args: Any*) = StrParser(sc.s(args:_*)) -} +extension (sc: StringContext) + def p(args: Any*) = StrParser(sc.s(args:_*)) + // more convenient syntax for parser combinators -implicit def ParserOps[I : IsSeq, T](p: Parser[I, T]) = new { +extension [I, T](p: Parser[I, T])(using I => Seq[_]) { def ||(q : => Parser[I, T]) = new AltParser[I, T](p, q) def ~[S] (q : => Parser[I, S]) = new SeqParser[I, T, S](p, q) - def map[S](f: => T => S) = new MapParser[I, T, S](p, f) + def mapp[S](f: => T => S) = new MapParser[I, T, S](p, f) } + // the abstract syntax trees for the WHILE language abstract class Stmt abstract class AExp @@ -128,47 +125,47 @@ // arithmetic expressions lazy val AExp: Parser[String, AExp] = - (Te ~ p"+" ~ AExp).map[AExp]{ case x ~ _ ~ z => Aop("+", x, z) } || - (Te ~ p"-" ~ AExp).map[AExp]{ case x ~ _ ~ z => Aop("-", x, z) } || Te + (Te ~ p"+" ~ AExp).mapp[AExp]{ case x ~ _ ~ z => Aop("+", x, z) } || + (Te ~ p"-" ~ AExp).mapp[AExp]{ case x ~ _ ~ z => Aop("-", x, z) } || Te lazy val Te: Parser[String, AExp] = - (Fa ~ p"*" ~ Te).map[AExp]{ case x ~ _ ~ z => Aop("*", x, z) } || - (Fa ~ p"/" ~ Te).map[AExp]{ case x ~ _ ~ z => Aop("/", x, z) } || Fa + (Fa ~ p"*" ~ Te).mapp[AExp]{ case x ~ _ ~ z => Aop("*", x, z) } || + (Fa ~ p"/" ~ Te).mapp[AExp]{ case x ~ _ ~ z => Aop("/", x, z) } || Fa lazy val Fa: Parser[String, AExp] = - (p"(" ~ AExp ~ p")").map{ case _ ~ y ~ _ => y } || - IdParser.map(Var) || - NumParser.map(Num) + (p"(" ~ AExp ~ p")").mapp{ case _ ~ y ~ _ => y } || + IdParser.mapp(Var) || + NumParser.mapp(Num) // boolean expressions with some simple nesting lazy val BExp: Parser[String, BExp] = - (AExp ~ p"==" ~ AExp).map[BExp]{ case x ~ _ ~ z => Bop("==", x, z) } || - (AExp ~ p"!=" ~ AExp).map[BExp]{ case x ~ _ ~ z => Bop("!=", x, z) } || - (AExp ~ p"<" ~ AExp).map[BExp]{ case x ~ _ ~ z => Bop("<", x, z) } || - (AExp ~ p">" ~ AExp).map[BExp]{ case x ~ _ ~ z => Bop(">", x, z) } || - (p"(" ~ BExp ~ p")" ~ p"&&" ~ BExp).map[BExp]{ case _ ~ y ~ _ ~ _ ~ v => And(y, v) } || - (p"(" ~ BExp ~ p")" ~ p"||" ~ BExp).map[BExp]{ case _ ~ y ~ _ ~ _ ~ v => Or(y, v) } || - (p"true".map[BExp]{ _ => True }) || - (p"false".map[BExp]{ _ => False }) || - (p"(" ~ BExp ~ p")").map[BExp]{ case _ ~ x ~ _ => x } + (AExp ~ p"==" ~ AExp).mapp[BExp]{ case x ~ _ ~ z => Bop("==", x, z) } || + (AExp ~ p"!=" ~ AExp).mapp[BExp]{ case x ~ _ ~ z => Bop("!=", x, z) } || + (AExp ~ p"<" ~ AExp).mapp[BExp]{ case x ~ _ ~ z => Bop("<", x, z) } || + (AExp ~ p">" ~ AExp).mapp[BExp]{ case x ~ _ ~ z => Bop(">", x, z) } || + (p"(" ~ BExp ~ p")" ~ p"&&" ~ BExp).mapp[BExp]{ case _ ~ y ~ _ ~ _ ~ v => And(y, v) } || + (p"(" ~ BExp ~ p")" ~ p"||" ~ BExp).mapp[BExp]{ case _ ~ y ~ _ ~ _ ~ v => Or(y, v) } || + (p"true".mapp[BExp]{ _ => True }) || + (p"false".mapp[BExp]{ _ => False }) || + (p"(" ~ BExp ~ p")").mapp[BExp]{ case _ ~ x ~ _ => x } // a single statement lazy val Stmt: Parser[String, Stmt] = - ((p"skip".map[Stmt]{_ => Skip }) || - (IdParser ~ p":=" ~ AExp).map[Stmt]{ case x ~ _ ~ z => Assign(x, z) } || - (p"write(" ~ IdParser ~ p")").map[Stmt]{ case _ ~ y ~ _ => Write(y) } || + ((p"skip".mapp[Stmt]{_ => Skip }) || + (IdParser ~ p":=" ~ AExp).mapp[Stmt]{ case x ~ _ ~ z => Assign(x, z) } || + (p"write(" ~ IdParser ~ p")").mapp[Stmt]{ case _ ~ y ~ _ => Write(y) } || (p"if" ~ BExp ~ p"then" ~ Block ~ p"else" ~ Block) - .map[Stmt]{ case _ ~ y ~ _ ~ u ~ _ ~ w => If(y, u, w) } || - (p"while" ~ BExp ~ p"do" ~ Block).map[Stmt]{ case _ ~ y ~ _ ~ w => While(y, w) }) + .mapp[Stmt]{ case _ ~ y ~ _ ~ u ~ _ ~ w => If(y, u, w) } || + (p"while" ~ BExp ~ p"do" ~ Block).mapp[Stmt]{ case _ ~ y ~ _ ~ w => While(y, w) }) // statements lazy val Stmts: Parser[String, Block] = - (Stmt ~ p";" ~ Stmts).map[Block]{ case x ~ _ ~ z => x :: z } || - (Stmt.map[Block]{ s => List(s) }) + (Stmt ~ p";" ~ Stmts).mapp[Block]{ case x ~ _ ~ z => x :: z } || + (Stmt.mapp[Block]{ s => List(s) }) // blocks (enclosed in curly braces) lazy val Block: Parser[String, Block] = - ((p"{" ~ Stmts ~ p"}").map{ case _ ~ y ~ _ => y } || - (Stmt.map(s => List(s)))) + ((p"{" ~ Stmts ~ p"}").mapp{ case _ ~ y ~ _ => y } || + (Stmt.mapp(s => List(s)))) // Examples @@ -273,8 +270,3 @@ println(eval(Stmts.parse_all(primes).head)) - - - - -// runs with amm2 and amm3