progs/pprint/tree.sc
changeset 742 b5b5583a3a08
child 873 a25da86f7c8c
--- /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("&middot")), 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("<i>r<sub>1</sub></i>"), SPECIAL("<i>r<sub>2</sub></i>")))
+val r2 = ALT(SPECIAL("<i>r<sub>1</sub></i>"), STAR(SPECIAL("<i>r<sub>2</sub></i>")))
+
+@main
+def main(fname: String) = {
+  val content = index(List(r1))
+  write.over(pwd / fname, content)
+}