progs/pprint/tree.sc
author Christian Urban <christian.urban@kcl.ac.uk>
Mon, 29 Aug 2022 01:16:32 +0200
changeset 873 a25da86f7c8c
parent 742 b5b5583a3a08
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
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     2
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     3
// regular expressions including records
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     4
abstract class Rexp 
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     5
case object ZERO extends Rexp
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     6
case object ONE extends Rexp
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     7
case class CHAR(c: Char) extends Rexp
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     8
case class ALT(r1: Rexp, r2: Rexp) extends Rexp 
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     9
case class SEQ(r1: Rexp, r2: Rexp) extends Rexp 
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    10
case class STAR(r: Rexp) extends Rexp 
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    11
case class SPECIAL(s: String) extends Rexp
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    12
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    13
def nullable (r: Rexp) : Boolean = r match {
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    14
  case ZERO => false
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    15
  case ONE => true
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    16
  case CHAR(_) => false
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    17
  case ALT(r1, r2) => nullable(r1) || nullable(r2)
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    18
  case SEQ(r1, r2) => nullable(r1) && nullable(r2)
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    19
  case STAR(_) => true
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    20
}
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    21
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    22
def der(c: Char, r: Rexp) : Rexp = r match {
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    23
  case ZERO => ZERO
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    24
  case ONE => ZERO
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    25
  case CHAR(d) => if (c == d) ONE else ZERO
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    26
  case ALT(r1, r2) => ALT(der(c, r1), der(c, r2))
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    27
  case SEQ(r1, r2) => 
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    28
    if (nullable(r1)) ALT(SEQ(der(c, r1), r2), der(c, r2))
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    29
    else SEQ(der(c, r1), r2)
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    30
  case STAR(r1) => SEQ(der(c, r1), STAR(r1))
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    31
}
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    32
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    33
def ders(s: List[Char], r: Rexp) : Rexp = s match {
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    34
  case Nil => r
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    35
  case c::s => ders(s, der(c, r))
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 simp(r: Rexp) : Rexp = r match {
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    39
  case ALT(r1, r2) => (simp(r1), simp(r2)) match {
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    40
    case (ZERO, r2s) => r2s
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    41
    case (r1s, ZERO) => r1s
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    42
    case (r1s, r2s) => if (r1s == r2s) r1s else ALT (r1s, r2s)
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    43
  }
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    44
  case SEQ(r1, r2) =>  (simp(r1), simp(r2)) match {
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    45
    case (ZERO, _) => ZERO
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    46
    case (_, ZERO) => ZERO
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    47
    case (ONE, r2s) => r2s
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    48
    case (r1s, ONE) => r1s
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    49
    case (r1s, r2s) => SEQ(r1s, r2s)
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    50
  }
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    51
  case r => r
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    52
}
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    53
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    54
def ders_simp(s: List[Char], r: Rexp) : Rexp = s match {
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    55
  case Nil => r
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    56
  case c::s => ders_simp(s, simp(der(c, 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
873
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
    60
// scalatags 
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
    61
import $ivy.`com.lihaoyi::scalatags:0.8.2` 
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
    62
import scalatags.Text.all._
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
    63
import scalatags.Text._
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
    64
742
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) = {
873
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   107
  val content = index(List(r1, r2, evil2))
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   108
  os.write.over(os.pwd / fname, content)
742
b5b5583a3a08 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   109
}  
873
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   110
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   111
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   112
  
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   113
// scalatags 
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   114
import $ivy.`com.lihaoyi::scalatags:0.8.2` 
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   115
import scalatags.Text.all._
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   116
import scalatags.Text._
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   117
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   118
def pp(r: Rexp) : TypedTag[String] = r match {
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   119
  case CHAR(c) => li(code(c.toString))
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   120
  case ALTs(rs) => li(code("+"), ul(rs.map(pp)))
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   121
  case SEQs(rs) => li(code(raw("&middot")), ul(rs.map(pp)))
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   122
  case STAR(r1) => li(code("*"), ul(pp(r1)))
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   123
  case ZERO => li(code("0"))
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   124
  case ONE => li(code("1"))
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   125
  //case SPECIAL(s) => li(code(raw(s)))
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   126
} 
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   127
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   128
def mktree(r: Rexp) = 
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   129
   ul(cls := "tree")(pp(r))
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   130
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   131
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   132
def index(rs: List[Rexp]) = 
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   133
  html(
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   134
    head(link(rel := "stylesheet", href := "./style.css")),
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   135
    body(rs.map(mktree))
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   136
  )
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   137
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   138
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   139
@main
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   140
def main(fname: String) = {
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   141
  val r = ("a" | "ab" | "a") ~ ("c" | "bc")
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   142
  val strs = List("","a","ab","abc")
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   143
  val content = index(strs.map(s => ders(s.toList, r)))
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   144
  os.write.over(os.pwd / fname, content)
a25da86f7c8c updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   145
}