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