import jsy.lab6.JsyInterpreter
import jsy.lab6.JsyParser
object Lab6 extends jsy.util.JsyApplication {
import jsy.lab6.ast._
/*
* CSCI 3155: Lab 6
*
*
* Partner: U): ParseResult
* }
* case class Success[+T](result: T, next: Input) extends ParseResult[T]
* case class Failure(next: Input) extends ParseResult[Nothing]
*/
def re(next: Input): ParseResult[RegExpr] = union(next)
def union(next: Input): ParseResult[RegExpr] = intersect(next) match {
case Success(r, next) => {
def unions(acc: RegExpr, next: Input): ParseResult[RegExpr] =
if (next.atEnd) Success(acc, next)
else (next.first, next.rest) match {
case ('|', next) => intersect(next) match {
case Success(r, next) => unions(RUnion(acc, r), next)
case _ => Failure("expected intersect", next)
}
case _ => Success(acc, next)
}
unions(r, next)
}
case _ => Failure("expected intersect", next)
}
def intersect(next: Input): ParseResult[RegExpr] = throw new UnsupportedOperationException
def concat(next: Input): ParseResult[RegExpr] = throw new UnsupportedOperationException
def not(next: Input): ParseResult[RegExpr] = throw new UnsupportedOperationException
def star(next: Input): ParseResult[RegExpr] = throw new UnsupportedOperationException
/* This set is useful to check if a Char is/is not a regular expression
meta-language character. Use delimiters.contains(c) for a Char c. */
val delimiters = Set('|', '&', '~', '*', '+', '?', '!', '#', '.', '(', ')')
def atom(next: Input): ParseResult[RegExpr] = throw new UnsupportedOperationException
/* External Interface */
def parse(next: Input): RegExpr = re(next) match {
case Success(r, next) if (next.atEnd) => r
case Success(_, next) => throw new SyntaxError("remaining input", next.pos)
case Failure(msg, next) => throw new SyntaxError(msg, next.pos)
}
def parse(s: String): RegExpr = parse(new CharSequenceReader(s))
}
/*** Regular Expression Matching ***/
def retest(re: RegExpr, s: String): Boolean = {
def test(re: RegExpr, chars: List[Char], sc: List[Char] => Boolean): Boolean = (re, chars) match {
/* Basic Operators */
case (RNoString, _) => throw new UnsupportedOperationException
case (REmptyString, _) => throw new UnsupportedOperationException
case (RSingle(_), Nil) => throw new UnsupportedOperationException
case (RSingle(c1), c2 :: t) => throw new UnsupportedOperationException
case (RConcat(re1, re2), _) => throw new UnsupportedOperationException
case (RUnion(re1, re2), _) => throw new UnsupportedOperationException
case (RStar(re1), _) => throw new UnsupportedOperationException
/* Extended Operators */
case (RAnyChar, Nil) => false
case (RAnyChar, _ :: t) => sc(t)
case (RPlus(re1), _) => throw new UnsupportedOperationException
case (ROption(re1), _) => throw new UnsupportedOperationException
/***** Extra Credit Cases *****/
case (RIntersect(re1, re2), _) => throw new UnsupportedOperationException
case (RNeg(re1), _) => throw new UnsupportedOperationException
}
test(re, s.toList, { chars => chars.isEmpty })
}
/*** JavaScripty Interpreter ***/
/* This part is optional and only for fun.
*
* If you want your own complete JavaScripty interpreter, you can copy your
* Lab 5 interpreter here and extend it for the Lab 6 constructs.
*
* By default, a reference JavaScripty interpreter will run using your
* regular expression tester.
*/
object MyInterpreter extends jsy.lab6.Interpreter {
/* Type checking. */
def typeInfer(env: Map[String,(Mutability,Typ)], e: Expr): Typ =
throw new UnsupportedOperationException
/* A small-step transition. */
def stepre(retest: (RegExpr, String) => Boolean)(e: Expr): DoWith[Mem, Expr] = {
def step(e: Expr): DoWith[Mem, Expr] = {
require(!isValue(e), "stepping on a value: %s".format(e))
throw new UnsupportedOperationException
}
step(e)
}
}
/*** External Interfaces ***/
this.debug = true // comment this out or set to false if you don't want print debugging information
this.maxSteps = Some(500) // comment this out or set to None to not bound the number of steps.
var useReferenceRegExprParser = false /* set to true to use the reference parser */
var useReferenceJsyInterpreter = true /* set to false to use your JavaScripty interpreter */
this.flagOptions = this.flagOptions ++ List(
("ref-reparser", jsy.util.options.SetBool(b => useReferenceRegExprParser = b, Some(b => useReferenceRegExprParser == b)), "using the reference regular expression parser"),
("ref-jsyinterp", jsy.util.options.SetBool(b => useReferenceJsyInterpreter = b, Some(b => useReferenceJsyInterpreter == b)), "using the reference JavaScripty interpreter")
)
// Select the interpreter to use based on the useReferenceJsyInterpreter flag
val interpreter: jsy.lab6.Interpreter =
if (useReferenceJsyInterpreter) jsy.lab6.JsyInterpreter else MyInterpreter
def inferType(e: Expr): Typ = {
if (debug) {
println("------------------------------------------------------------")
println("Type checking: %s ...".format(e))
}
val t = interpreter.typeInfer(Map.empty, e)
if (debug) {
println("Type: " + pretty(t))
}
t
}
// Interface to run your small-step interpreter and print out the steps of evaluation if debugging.
case class TerminationError(e: Expr) extends Exception {
override def toString = JsyParser.formatErrorMessage(e.pos, "TerminationError", "run out of steps in evaluating " + e)
}
def iterateStep(e: Expr): Expr = {
require(closed(e), "not a closed expression: free variables: %s".format(freeVars(e)) )
val step: Expr => DoWith[Mem, Expr] = interpreter.stepre(retest)
def loop(e: Expr, n: Int): DoWith[Mem,Expr] =
if (Some(n) == maxSteps) throw TerminationError(e)
else if (isValue(e)) doreturn( e )
else {
for {
m