// 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("<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)
}