progs/pprint/tree.sc
author Christian Urban <christian.urban@kcl.ac.uk>
Sun, 17 Sep 2023 19:12:57 +0100
changeset 919 d16037caa8fd
parent 873 c885ed3c39cf
permissions -rw-r--r--
updated
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
742
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     1
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     2
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     3
// regular expressions including records
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     4
abstract class Rexp 
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     5
case object ZERO extends Rexp
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     6
case object ONE extends Rexp
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     7
case class CHAR(c: Char) extends Rexp
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     8
case class ALT(r1: Rexp, r2: Rexp) extends Rexp 
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     9
case class SEQ(r1: Rexp, r2: Rexp) extends Rexp 
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    10
case class STAR(r: Rexp) extends Rexp 
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    11
case class SPECIAL(s: String) extends Rexp
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    12
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    13
def nullable (r: Rexp) : Boolean = r match {
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    14
  case ZERO => false
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    15
  case ONE => true
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    16
  case CHAR(_) => false
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    17
  case ALT(r1, r2) => nullable(r1) || nullable(r2)
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    18
  case SEQ(r1, r2) => nullable(r1) && nullable(r2)
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    19
  case STAR(_) => true
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    20
}
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    21
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    22
def der(c: Char, r: Rexp) : Rexp = r match {
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    23
  case ZERO => ZERO
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    24
  case ONE => ZERO
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    25
  case CHAR(d) => if (c == d) ONE else ZERO
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    26
  case ALT(r1, r2) => ALT(der(c, r1), der(c, r2))
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    27
  case SEQ(r1, r2) => 
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    28
    if (nullable(r1)) ALT(SEQ(der(c, r1), r2), der(c, r2))
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    29
    else SEQ(der(c, r1), r2)
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    30
  case STAR(r1) => SEQ(der(c, r1), STAR(r1))
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    31
}
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    32
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    33
def ders(s: List[Char], r: Rexp) : Rexp = s match {
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    34
  case Nil => r
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    35
  case c::s => ders(s, der(c, r))
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    36
}
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    37
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    38
def simp(r: Rexp) : Rexp = r match {
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    39
  case ALT(r1, r2) => (simp(r1), simp(r2)) match {
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    40
    case (ZERO, r2s) => r2s
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    41
    case (r1s, ZERO) => r1s
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    42
    case (r1s, r2s) => if (r1s == r2s) r1s else ALT (r1s, r2s)
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    43
  }
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    44
  case SEQ(r1, r2) =>  (simp(r1), simp(r2)) match {
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    45
    case (ZERO, _) => ZERO
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    46
    case (_, ZERO) => ZERO
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    47
    case (ONE, r2s) => r2s
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    48
    case (r1s, ONE) => r1s
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    49
    case (r1s, r2s) => SEQ(r1s, r2s)
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    50
  }
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    51
  case r => r
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    52
}
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    53
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    54
def ders_simp(s: List[Char], r: Rexp) : Rexp = s match {
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    55
  case Nil => r
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    56
  case c::s => ders_simp(s, simp(der(c, r)))
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    57
}
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    58
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    59
873
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
    60
// scalatags 
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
    61
import $ivy.`com.lihaoyi::scalatags:0.8.2` 
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
    62
import scalatags.Text.all._
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
    63
import scalatags.Text._
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
    64
742
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    65
def pp(r: Rexp) : TypedTag[String] = r match {
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    66
  case CHAR(c) => li(code(c.toString))
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    67
  case ALT(r1, r2) => li(code("+"), ul(pp(r1), pp(r2)))
155426396b5f 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)))
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    69
  case STAR(r1) => li(code("*"), ul(pp(r1)))
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    70
  case ZERO => li(code("0"))
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    71
  case ONE => li(code("1"))
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    72
  case SPECIAL(s) => li(code(raw(s)))
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    73
} 
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    74
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    75
def mktree(r: Rexp) = 
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    76
   ul(cls := "tree")(pp(r))
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    77
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    78
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    79
def index(rs: List[Rexp]) = 
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    80
  html(
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    81
    head(link(rel := "stylesheet", href := "./style.css")),
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    82
    body(rs.map(mktree))
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    83
  )
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    84
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    85
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    86
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    87
/*
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    88
println(index(List(simple, test, evil2)))
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    89
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    90
val simple = CHAR('a')
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    91
val test = ALT(CHAR('a'), CHAR('b'))
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    92
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    93
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    94
write.over(pwd/"t1.html", 
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    95
    index(List(evil2, 
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    96
               ders("a".toList, evil2),
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    97
               ders("aa".toList, evil2),
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    98
               ders("aaa".toList, evil2))))
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    99
*/
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   100
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   101
val evil2 = SEQ(STAR(STAR(CHAR('a'))), CHAR('b'))
155426396b5f 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>")))
155426396b5f 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>")))
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   104
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   105
@main
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   106
def main(fname: String) = {
873
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   107
  val content = index(List(r1, r2, evil2))
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   108
  os.write.over(os.pwd / fname, content)
742
155426396b5f updated
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   109
}  
873
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   110
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   111
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   112
  
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   113
// scalatags 
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   114
import $ivy.`com.lihaoyi::scalatags:0.8.2` 
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   115
import scalatags.Text.all._
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   116
import scalatags.Text._
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   117
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   118
def pp(r: Rexp) : TypedTag[String] = r match {
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   119
  case CHAR(c) => li(code(c.toString))
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   120
  case ALTs(rs) => li(code("+"), ul(rs.map(pp)))
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   121
  case SEQs(rs) => li(code(raw("&middot")), ul(rs.map(pp)))
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   122
  case STAR(r1) => li(code("*"), ul(pp(r1)))
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   123
  case ZERO => li(code("0"))
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   124
  case ONE => li(code("1"))
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   125
  //case SPECIAL(s) => li(code(raw(s)))
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   126
} 
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   127
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   128
def mktree(r: Rexp) = 
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   129
   ul(cls := "tree")(pp(r))
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   130
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   131
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   132
def index(rs: List[Rexp]) = 
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   133
  html(
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   134
    head(link(rel := "stylesheet", href := "./style.css")),
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   135
    body(rs.map(mktree))
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   136
  )
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   137
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   138
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   139
@main
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   140
def main(fname: String) = {
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   141
  val r = ("a" | "ab" | "a") ~ ("c" | "bc")
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   142
  val strs = List("","a","ab","abc")
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   143
  val content = index(strs.map(s => ders(s.toList, r)))
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   144
  os.write.over(os.pwd / fname, content)
c885ed3c39cf updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 742
diff changeset
   145
}