solutions/cw5/fun_tokens.sc
changeset 920 7af2eea19646
parent 903 2f86ebda3629
--- a/solutions/cw5/fun_tokens.sc	Sun Sep 17 19:12:57 2023 +0100
+++ b/solutions/cw5/fun_tokens.sc	Tue Sep 19 09:54:41 2023 +0100
@@ -33,9 +33,6 @@
 case class Left(v: Val) extends Val
 case class Right(v: Val) extends Val
 case class Stars(vs: List[Val]) extends Val
-case class Opt(v: Val) extends Val
-case class Pls(vs: List[Val]) extends Val
-case class Nt(vs: List[Val]) extends Val
 case class Rec(x: String, v: Val) extends Val
 
 // some convenience for typing in regular expressions
@@ -45,30 +42,26 @@
   case c::vs => SEQ(CHAR(c), charlist2rexp(vs))
 }
 
-implicit def string2rexp(s : String) : Rexp =
+implicit def string2rexp(s : String) : Rexp = 
   charlist2rexp(s.toList)
 
-implicit def RexpOps(r: Rexp) = new {
+extension (r: Rexp) {
   def | (s: Rexp) = ALT(r, s)
   def % = STAR(r)
-  def ? = OPTIONAL(r)
   def + = PLUS(r)
-  def ^ (n: Int) = NTIMES(r, n)
   def ~ (s: Rexp) = SEQ(r, s)
 }
 
-implicit def stringOps(s: String) = new {
+extension (s: String) {
   def | (r: Rexp) = ALT(s, r)
   def | (r: String) = ALT(s, r)
   def % = STAR(s)
-  def ? = OPTIONAL(s)
-  def + = PLUS(s)
-  def ^ (n: Int) = NTIMES(s, n)
   def ~ (r: Rexp) = SEQ(s, r)
   def ~ (r: String) = SEQ(s, r)
   def $ (r: Rexp) = RECD(s, r)
 }
 
+
 def nullable(r: Rexp) : Boolean = r match {
   case ZERO => false
   case ONE => true
@@ -107,9 +100,6 @@
   case Right(v) => flatten(v)
   case Sequ(v1, v2) => flatten(v1) ++ flatten(v2)
   case Stars(vs) => vs.map(flatten).mkString
-  case Opt(v) => flatten(v)
-  case Pls(vs) => vs.map(flatten).mkString
-  case Nt(vs) => vs.map(flatten).mkString
   case Rec(_, v) => flatten(v)
 }
 
@@ -122,9 +112,6 @@
   case Right(v) => env(v)
   case Sequ(v1, v2) => env(v1) ::: env(v2)
   case Stars(vs) => vs.flatMap(env)
-  case Opt(v) => env(v)
-  case Pls(vs) => vs.flatMap(env)
-  case Nt(vs) => vs.flatMap(env)
   case Rec(x, v) => (x, flatten(v))::env(v)
 }
 
@@ -132,20 +119,21 @@
 // The injection and mkeps part of the lexer
 //===========================================
 
+// Mkeps
 def mkeps(r: Rexp) : Val = r match {
   case ONE => Empty
-  case RANGE(chars) => throw new Exception("lexing error")  // this will never be called but the coursework asks for it so...
-  case ALT(r1, r2) =>
+  case ALT(r1, r2) => 
     if (nullable(r1)) Left(mkeps(r1)) else Right(mkeps(r2))
   case SEQ(r1, r2) => Sequ(mkeps(r1), mkeps(r2))
   case STAR(r) => Stars(Nil)
-  case OPTIONAL(r) => Opt(Empty)
-  case PLUS(r) => Pls(List(mkeps(r))) // scala define a list with one element
-  case NTIMES(r, n) => if (n == 0) Nt(Nil) else Nt(List.fill(n)(mkeps(r))) // wrong
   case RECD(x, r) => Rec(x, mkeps(r))
-  case _ => throw new Exception("lexing error")
+
+  case PLUS(r) => Stars(List(mkeps(r)))   // the first copy must match the empty string
+  case OPTIONAL(r) => if (nullable(r)) Stars(List(mkeps(r))) else Stars(Nil)
+  case NTIMES(r, i) => Stars(List.fill(i)(mkeps(r)))
 }
 
+// Inj
 def inj(r: Rexp, c: Char, v: Val) : Val = (r, v) match {
   case (STAR(r), Sequ(v1, Stars(vs))) => Stars(inj(r, c, v1)::vs)
   case (SEQ(r1, r2), Sequ(v1, v2)) => Sequ(inj(r1, c, v1), v2)
@@ -153,14 +141,16 @@
   case (SEQ(r1, r2), Right(v2)) => Sequ(mkeps(r1), inj(r2, c, v2))
   case (ALT(r1, r2), Left(v1)) => Left(inj(r1, c, v1))
   case (ALT(r1, r2), Right(v2)) => Right(inj(r2, c, v2))
-  case (CHAR(d), Empty) => Chr(c)
-  case (RANGE(chars), Empty) => Chr(c)
-  case (OPTIONAL(r1), v) => Opt(inj(r1, c, v))
-  case (PLUS(r1), Sequ(v1, Stars(vs))) => Pls(inj(r1, c, v1)::vs)
-  case (NTIMES(r1, n), Sequ(v1, Nt(vs))) => Nt(inj(r1, c, v1)::vs)
+  case (CHAR(d), Empty) => Chr(c) 
   case (RECD(x, r1), _) => Rec(x, inj(r1, c, v))
+
+  case (RANGE(_), Empty) => Chr(c)
+  case (PLUS(r), Sequ(v1, Stars(vs))) => Stars(inj(r, c, v1)::vs)
+  case (OPTIONAL(r), v1) => Stars(List(inj(r, c, v1)))
+  case (NTIMES(r, n), Sequ(v1, Stars(vs))) => Stars(inj(r, c, v1)::vs)
 }
 
+
 // some "rectification" functions for simplification
 def F_ID(v: Val): Val = v
 def F_RIGHT(f: Val => Val) = (v:Val) => Right(f(v))