package edu.uwm.cs import scala.collection.mutable.ListBuffer import edu.uwm.cs.cool.tree._ object CoolParser extends CoolLexer { private type E = Expression private var superclassName: Symbol = _ private var superclassActuals: List[E] = Nil private var nativeConstructor = false private var inheritable = true private val constructor = new ListBuffer[E] // grammar def programDef(file: Symbol) = (classDef(file)+) ^^ program def classDef(file: Symbol) = CLASS ~> TYPEID ~! formals ~! superclass ~! ("{" ~> featureList <~ "}") ^^ flatten4 { (name, formals, parent, dirtyFeatures) => val features = for { optF <- dirtyFeatures if optF.isDefined } yield optF.get class_(name, parent, makeConstructor(name, formals) :: features, file) } def superclass = opt(EXTENDS ~> typeOrNative) ^^ { n => superclassName = n getOrElse 'Object if (superclassName eq null) nativeConstructor = true superclassName } def typeOrNative = ( TYPEID ~! actuals ^^ flatten2 { (id, actuals) => superclassActuals = actuals id } | NATIVE ^^^ null ) def featureList = ( feature <~ ";" ^^ { Some(_) } | NATIVE ~ ";" ^^ { x => nativeConstructor = true inheritable = false None } | "{" ~> blockDef <~ "}" ^^ { b => constructor += block(b) None } )* // empty classes? def feature = ( (OVERRIDE?) ~ (DEF ~> OBJECTID) ~! formals ~! (":" ~> TYPEID) ~! initOrNative ^^ flatten5 { (over, name, formals, ofType, expr) => method(over.isDefined, name, formals, ofType, expr) } | (varDecl ^^ flatten2 { attr(_, _) }) ~ ("=" ~> expr) ^^ flatten2 { (a, init) => constructor += assign(a.name, init) a } | VAR ~> OBJECTID <~ ":" ~! NATIVE ^^ { name => nativeConstructor = true inheritable = false attr(name, 'native) } ) def initOrNative = "=" ~> expr | NATIVE ^^^ no_expr() def varDecl = VAR ~> OBJECTID ~ (":" ~> TYPEID) def formals = "(" ~> repsep(formalDef, ",") <~ ")" def formalDef = OBJECTID ~! (":" ~> TYPEID) ^^ formal def expr: Parser[E] = ( IF ~> ("(" ~> expr <~ ")") ~! expr ~! (ELSE ~> expr) ^^ cond | exprNoMatch ~ rep(MATCH ~> "{" ~> caseList <~ "}" ^^ { c => typcase(_:E, c) }) ^^ collapse ) def exprNoMatch = rep(OBJECTID <~ "=" ^^ { n => assign(n, _:E) }) ~ exprNoAssign ^^ collapseInverse def exprNoAssign = exprNoEq ~ opt( EQ ~> exprNoEq ^^ { e => eql(_:E, e) } | EQUALS ~> exprNoEq ^^ { e => dispatch(_:E, 'equals, e :: Nil) } | LE ~> exprNoEq ^^ { e => leq(_:E, e) } | "<" ~> exprNoEq ^^ { e => lt(_:E, e) } ) ^^ { case e ~ Some(f) => f(e) case e ~ None => e } def exprNoEq = exprNoAdd ~ rep( "+" ~> exprNoAdd ^^ { e => add(_:E, e) } | "-" ~> exprNoAdd ^^ { e => sub(_:E, e) } ) ^^ collapse def exprNoAdd = exprNoMul ~ rep( "*" ~> exprNoMul ^^ { e => mul(_:E, e) } | "/" ~> exprNoMul ^^ { e => div(_:E, e) } ) ^^ collapse def exprNoMul = rep("-" ^^ { s => neg(_) } | "!" ^^ { s => comp(_) }) ~ exprNoUnary ^^ collapseInverse def exprNoUnary = ( SUPER ~> "." ~> OBJECTID ~ actuals ^^ flatten2 { (name, a) => static_dispatch(variable('this), superclassName, name, a) } | exprNoDispatch ~ rep("." ~> OBJECTID ~ actuals ^^ flatten2 { (name, a) => dispatch(_:E, name, a) }) ^^ collapse ) def exprNoDispatch = ( WHILE ~> ("(" ~> expr <~ ")") ~! expr ^^ loop | ("{" ~> blockDef <~ "}") ^^ block | NEW ~> TYPEID ~! actuals ^^ flatten2 { (name, actuals) => dispatch(new_(name), name, actuals) } | NULL ^^^ unit() | INT_CONST ^^ int_const | STR_CONST ^^ string_const | (TRUE | FALSE) ^^ bool_const | OBJECTID ~ actuals ^^ flatten2 { (name, actuals) => dispatch(variable('this), name, actuals) } | OBJECTID ^^ variable | ("(" ~> expr <~ ")") ^^ { e => e } ) def blockDef: Parser[List[E]] = ( varDecl ~! ("=" ~> expr <~ ";") ~! blockDef ^^ flatten4 { (name, ofType, init, expr) => let(name, ofType, init, block(expr)) :: Nil } | expr ~! (";" ~> blockDef | success(Nil)) ^^ flatten2 { _ :: _ } ) def actuals = "(" ~> repsep(expr, ",") <~ ")" def caseList = (CASE ~> (OBJECTID <~ ":") ~! TYPEID ~! (ARROW ~> expr) ^^ branch)+ // grammar ends def makeConstructor(name: Symbol, formals: List[Formal]) = { val body = if (nativeConstructor) no_expr() else { val superCall = static_dispatch(variable('this), superclassName, superclassName, superclassActuals) block(superCall :: (constructor + variable('this)).toList) } nativeConstructor = false constructor.clear method(false, name, formals, name, body) } /** * Collapse tail expressions into a left-leaning tree. */ private def collapse(p: ~[E, List[E=>E]]) = p match { case e ~ ls => innerCollapse(e, ls) } private def collapseInverse(p: ~[List[E=>E], E]) = p match { case ls ~ e => innerCollapse(e, ls) } private def innerCollapse(e: E, ls: List[E=>E]): E = ls match { case f :: tail => innerCollapse(f(e), tail) case Nil => e } }