diff -r e66bd5c563eb -r b5b5583a3a08 progs/pprint/tree.sc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/progs/pprint/tree.sc Thu Jul 30 13:50:54 2020 +0100
@@ -0,0 +1,109 @@
+// scalatags
+import ammonite.ops._
+
+import $ivy.`com.lihaoyi::scalatags:0.8.2`
+import scalatags.Text.all._
+import scalatags.Text._
+
+// regular expressions including records
+abstract class Rexp
+case object ZERO extends Rexp
+case object ONE extends Rexp
+case class CHAR(c: Char) extends Rexp
+case class ALT(r1: Rexp, r2: Rexp) extends Rexp
+case class SEQ(r1: Rexp, r2: Rexp) extends Rexp
+case class STAR(r: Rexp) extends Rexp
+case class SPECIAL(s: String) extends Rexp
+
+def nullable (r: Rexp) : Boolean = r match {
+ case ZERO => false
+ case ONE => true
+ case CHAR(_) => false
+ case ALT(r1, r2) => nullable(r1) || nullable(r2)
+ case SEQ(r1, r2) => nullable(r1) && nullable(r2)
+ case STAR(_) => true
+}
+
+def der(c: Char, r: Rexp) : Rexp = r match {
+ case ZERO => ZERO
+ case ONE => ZERO
+ case CHAR(d) => if (c == d) ONE else ZERO
+ case ALT(r1, r2) => ALT(der(c, r1), der(c, r2))
+ case SEQ(r1, r2) =>
+ if (nullable(r1)) ALT(SEQ(der(c, r1), r2), der(c, r2))
+ else SEQ(der(c, r1), r2)
+ case STAR(r1) => SEQ(der(c, r1), STAR(r1))
+}
+
+def ders(s: List[Char], r: Rexp) : Rexp = s match {
+ case Nil => r
+ case c::s => ders(s, der(c, r))
+}
+
+def simp(r: Rexp) : Rexp = r match {
+ case ALT(r1, r2) => (simp(r1), simp(r2)) match {
+ case (ZERO, r2s) => r2s
+ case (r1s, ZERO) => r1s
+ case (r1s, r2s) => if (r1s == r2s) r1s else ALT (r1s, r2s)
+ }
+ case SEQ(r1, r2) => (simp(r1), simp(r2)) match {
+ case (ZERO, _) => ZERO
+ case (_, ZERO) => ZERO
+ case (ONE, r2s) => r2s
+ case (r1s, ONE) => r1s
+ case (r1s, r2s) => SEQ(r1s, r2s)
+ }
+ case r => r
+}
+
+def ders_simp(s: List[Char], r: Rexp) : Rexp = s match {
+ case Nil => r
+ case c::s => ders_simp(s, simp(der(c, r)))
+}
+
+
+def pp(r: Rexp) : TypedTag[String] = r match {
+ case CHAR(c) => li(code(c.toString))
+ case ALT(r1, r2) => li(code("+"), ul(pp(r1), pp(r2)))
+ case SEQ(r1, r2) => li(code(raw("·")), ul(pp(r1), pp(r2)))
+ case STAR(r1) => li(code("*"), ul(pp(r1)))
+ case ZERO => li(code("0"))
+ case ONE => li(code("1"))
+ case SPECIAL(s) => li(code(raw(s)))
+}
+
+def mktree(r: Rexp) =
+ ul(cls := "tree")(pp(r))
+
+
+def index(rs: List[Rexp]) =
+ html(
+ head(link(rel := "stylesheet", href := "./style.css")),
+ body(rs.map(mktree))
+ )
+
+
+
+/*
+println(index(List(simple, test, evil2)))
+
+val simple = CHAR('a')
+val test = ALT(CHAR('a'), CHAR('b'))
+
+
+write.over(pwd/"t1.html",
+ index(List(evil2,
+ ders("a".toList, evil2),
+ ders("aa".toList, evil2),
+ ders("aaa".toList, evil2))))
+*/
+
+val evil2 = SEQ(STAR(STAR(CHAR('a'))), CHAR('b'))
+val r1 = STAR(ALT(SPECIAL("r1"), SPECIAL("r2")))
+val r2 = ALT(SPECIAL("r1"), STAR(SPECIAL("r2")))
+
+@main
+def main(fname: String) = {
+ val content = index(List(r1))
+ write.over(pwd / fname, content)
+}