progs/pprint/tree.sc
author Christian Urban <christian.urban@kcl.ac.uk>
Mon, 30 Aug 2021 15:50:27 +0100
changeset 829 dc3c35673e94
parent 742 b5b5583a3a08
child 873 a25da86f7c8c
permissions -rw-r--r--
updated
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
742
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     1
// scalatags 
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     2
import ammonite.ops._
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     3
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     4
import $ivy.`com.lihaoyi::scalatags:0.8.2` 
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     5
import scalatags.Text.all._
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     6
import scalatags.Text._
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     7
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     8
// regular expressions including records
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     9
abstract class Rexp 
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    10
case object ZERO extends Rexp
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    11
case object ONE extends Rexp
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    12
case class CHAR(c: Char) extends Rexp
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    13
case class ALT(r1: Rexp, r2: Rexp) extends Rexp 
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    14
case class SEQ(r1: Rexp, r2: Rexp) extends Rexp 
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    15
case class STAR(r: Rexp) extends Rexp 
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    16
case class SPECIAL(s: String) extends Rexp
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    17
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    18
def nullable (r: Rexp) : Boolean = r match {
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    19
  case ZERO => false
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    20
  case ONE => true
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    21
  case CHAR(_) => false
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    22
  case ALT(r1, r2) => nullable(r1) || nullable(r2)
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    23
  case SEQ(r1, r2) => nullable(r1) && nullable(r2)
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    24
  case STAR(_) => true
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    25
}
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    26
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    27
def der(c: Char, r: Rexp) : Rexp = r match {
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    28
  case ZERO => ZERO
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    29
  case ONE => ZERO
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    30
  case CHAR(d) => if (c == d) ONE else ZERO
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    31
  case ALT(r1, r2) => ALT(der(c, r1), der(c, r2))
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    32
  case SEQ(r1, r2) => 
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    33
    if (nullable(r1)) ALT(SEQ(der(c, r1), r2), der(c, r2))
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    34
    else SEQ(der(c, r1), r2)
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    35
  case STAR(r1) => SEQ(der(c, r1), STAR(r1))
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    36
}
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    37
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    38
def ders(s: List[Char], r: Rexp) : Rexp = s match {
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    39
  case Nil => r
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    40
  case c::s => ders(s, der(c, r))
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    41
}
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    42
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    43
def simp(r: Rexp) : Rexp = r match {
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    44
  case ALT(r1, r2) => (simp(r1), simp(r2)) match {
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    45
    case (ZERO, r2s) => r2s
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    46
    case (r1s, ZERO) => r1s
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    47
    case (r1s, r2s) => if (r1s == r2s) r1s else ALT (r1s, r2s)
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    48
  }
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    49
  case SEQ(r1, r2) =>  (simp(r1), simp(r2)) match {
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    50
    case (ZERO, _) => ZERO
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    51
    case (_, ZERO) => ZERO
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    52
    case (ONE, r2s) => r2s
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    53
    case (r1s, ONE) => r1s
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    54
    case (r1s, r2s) => SEQ(r1s, r2s)
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    55
  }
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    56
  case r => r
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    57
}
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    58
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    59
def ders_simp(s: List[Char], r: Rexp) : Rexp = s match {
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    60
  case Nil => r
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    61
  case c::s => ders_simp(s, simp(der(c, r)))
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    62
}
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    63
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    64
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    65
def pp(r: Rexp) : TypedTag[String] = r match {
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    66
  case CHAR(c) => li(code(c.toString))
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    67
  case ALT(r1, r2) => li(code("+"), ul(pp(r1), pp(r2)))
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    68
  case SEQ(r1, r2) => li(code(raw("&middot")), ul(pp(r1), pp(r2)))
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    69
  case STAR(r1) => li(code("*"), ul(pp(r1)))
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    70
  case ZERO => li(code("0"))
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    71
  case ONE => li(code("1"))
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    72
  case SPECIAL(s) => li(code(raw(s)))
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    73
} 
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    74
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    75
def mktree(r: Rexp) = 
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    76
   ul(cls := "tree")(pp(r))
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    77
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    78
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    79
def index(rs: List[Rexp]) = 
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    80
  html(
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    81
    head(link(rel := "stylesheet", href := "./style.css")),
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    82
    body(rs.map(mktree))
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    83
  )
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    84
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    85
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    86
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    87
/*
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    88
println(index(List(simple, test, evil2)))
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    89
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    90
val simple = CHAR('a')
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    91
val test = ALT(CHAR('a'), CHAR('b'))
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    92
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    93
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    94
write.over(pwd/"t1.html", 
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    95
    index(List(evil2, 
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    96
               ders("a".toList, evil2),
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    97
               ders("aa".toList, evil2),
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    98
               ders("aaa".toList, evil2))))
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    99
*/
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   100
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   101
val evil2 = SEQ(STAR(STAR(CHAR('a'))), CHAR('b'))
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   102
val r1 = STAR(ALT(SPECIAL("<i>r<sub>1</sub></i>"), SPECIAL("<i>r<sub>2</sub></i>")))
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   103
val r2 = ALT(SPECIAL("<i>r<sub>1</sub></i>"), STAR(SPECIAL("<i>r<sub>2</sub></i>")))
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   104
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   105
@main
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   106
def main(fname: String) = {
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   107
  val content = index(List(r1))
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   108
  write.over(pwd / fname, content)
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   109
}