| author | Christian Urban <christian.urban@kcl.ac.uk> | 
| Sat, 04 Dec 2021 00:41:31 +0000 | |
| changeset 859 | 2c6fa627df78 | 
| parent 742 | 155426396b5f | 
| permissions | -rw-r--r-- | 
| 90 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 1 | trait RegExp {
 | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 2 | def nullable: Boolean | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 3 | def derive(c: Char): RegExp | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 4 | } | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 5 | |
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 6 | case object Empty extends RegExp {
 | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 7 | def nullable = false | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 8 | def derive(c: Char) = Empty | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 9 | } | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 10 | |
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 11 | case object Eps extends RegExp {
 | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 12 | def nullable = true | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 13 | def derive(c: Char) = Empty | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 14 | } | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 15 | |
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 16 | case class Str(s: String) extends RegExp {
 | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 17 | def nullable = s.isEmpty | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 18 | def derive(c: Char) = | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 19 | if (s.isEmpty || s.head != c) Empty | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 20 | else Str(s.tail) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 21 | } | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 22 | |
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 23 | case class Cat(r: RegExp, s: RegExp) extends RegExp {
 | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 24 | def nullable = r.nullable && s.nullable | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 25 | def derive(c: Char) = | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 26 | if (r.nullable) Or(Cat(r.derive(c), s), s.derive(c)) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 27 | else Cat(r.derive(c), s) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 28 | } | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 29 | |
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 30 | case class Star(r: RegExp) extends RegExp {
 | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 31 | def nullable = true | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 32 | def derive(c: Char) = Cat(r.derive(c), this) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 33 | } | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 34 | |
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 35 | case class Or(r: RegExp, s: RegExp) extends RegExp {
 | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 36 | def nullable = r.nullable || s.nullable | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 37 | def derive(c: Char) = Or(r.derive(c), s.derive(c)) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 38 | } | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 39 | |
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 40 | case class And(r: RegExp, s: RegExp) extends RegExp {
 | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 41 | def nullable = r.nullable && s.nullable | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 42 | def derive(c: Char) = And(r.derive(c), s.derive(c)) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 43 | } | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 44 | |
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 45 | case class Not(r: RegExp) extends RegExp {
 | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 46 | def nullable = !r.nullable | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 47 | def derive(c: Char) = Not(r.derive(c)) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 48 | } | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 49 | |
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 50 | |
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 51 | |
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 52 | |
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 53 | object Matcher {
 | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 54 |   def matches(r: RegExp, s: String): Boolean = {
 | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 55 | if (s.isEmpty) r.nullable | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 56 | else matches(r.derive(s.head), s.tail) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 57 | } | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 58 | } | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 59 | |
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 60 | |
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 61 | object Pimps {
 | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 62 | implicit def string2RegExp(s: String) = Str(s) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 63 | |
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 64 |   implicit def regExpOps(r: RegExp) = new {
 | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 65 | def | (s: RegExp) = Or(r, s) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 66 | def & (s: RegExp) = And(r, s) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 67 | def % = Star(r) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 68 | def %(n: Int) = rep(r, n) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 69 | def ? = Or(Eps, r) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 70 | def ! = Not(r) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 71 | def ++ (s: RegExp) = Cat(r, s) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 72 | def ~ (s: String) = Matcher.matches(r, s) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 73 | } | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 74 | |
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 75 |   implicit def stringOps(s: String) = new {
 | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 76 | def | (r: RegExp) = Or(s, r) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 77 | def | (r: String) = Or(s, r) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 78 | def & (r: RegExp) = And(s, r) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 79 | def & (r: String) = And(s, r) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 80 | def % = Star(s) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 81 | def % (n: Int) = rep(Str(s), n) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 82 | def ? = Or(Eps, s) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 83 | def ! = Not(s) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 84 | def ++ (r: RegExp) = Cat(s, r) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 85 | def ++ (r: String) = Cat(s, r) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 86 | def ~ (t: String) = Matcher.matches(s, t) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 87 | } | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 88 | |
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 89 | def rep(r: RegExp, n: Int): RegExp = | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 90 | if (n <= 0) Star(r) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 91 | else Cat(r, rep(r, n - 1)) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 92 | } | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 93 | |
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 94 | |
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 95 | object Test {
 | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 96 | import Pimps._ | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 97 | |
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 98 | val digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 99 |   val int = ("+" | "-").? ++ digit.%(1)
 | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 100 |   val real = ("+" | "-").? ++ digit.%(1) ++ ("." ++ digit.%(1)).? ++ (("e" | "E") ++ ("+" | "-").? ++ digit.%(1)).?
 | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 101 | |
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 102 |   def main(args: Array[String]) {
 | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 103 |     val ints = List("0", "-4534", "+049", "99")
 | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 104 |     val reals = List("0.9", "-12.8", "+91.0", "9e12", "+9.21E-12", "-512E+01")
 | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 105 |     val errs = List("", "-", "+", "+-1", "-+2", "2-")
 | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 106 | |
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 107 | ints.foreach(s => assert(int ~ s)) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 108 | reals.foreach(s => assert(!(int ~ s))) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 109 | errs.foreach(s => assert(!(int ~ s))) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 110 | |
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 111 | ints.foreach(s => assert(real ~ s)) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 112 | reals.foreach(s => assert(real ~ s)) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 113 | errs.foreach(s => assert(!(real ~ s))) | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 114 | } | 
| 
e1f94216f39d
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 115 | } |